Aegidius
 Plüss   Aplulogo
     
 www.aplu.ch      Print Text 
© 2021, V10.4
 
  TCPCom Module
 
raspilogo
                TCPCom
 

 

An Event-Driven Socket Library
for Java and Python

 

The Importance of Computer and Communication Technologies

The exchange of data between computer systems plays an extremely important role in our interconnected world.  Therefore we often speak of the combined computer- and communication technologies that should be mastered. In this chapter you learn how to handle the data exchange between two computer systems using the TCP/IP protocol which is used in all Internet connections, for example the Web and all streaming services (data clouds, voice, music, video streaming).

The socket programming is based on the client-server model, which has already been described in some details on the TcpJLib and BtLib sites. Most important and somewhat unexpected is the fact that the communication partners, the server and the client, are not completely symmetrical. Rather, first the server program must be started before the client program can engage a connection to it. In order to identify the two computers on the Internet, its IP address is used. In addition, server and client specify one of 65536 communication channels (IP ports), that is selected with a number in the range 0..65535.

When the server starts, it creates a server socket (like a electrical plug) that uses a particular port and goes in a wait state. We say that the server is "listening" for an incoming client, so the server is in the LISTENING state. The client creates a client socket (the plug counterpart) and tries to establish a communication link to the server using its IP address and port number.

 

The Easy Way of Socket Programming Using Objects and Events

The library TCPCom simplifies the socket programming essentially, since it describes the current state of the server and the client with state variables and considers the change of the variables to be caused by events.  This programming model corresponds to the natural feeling of many people to describe the communication between two human partners. In the free download you find three versions of the library for Java SE, Android and Python and many demonstration examples. The Java SE and Python versions may also be used on the Raspberry Pi and the Java SE version on the Lego EV3 robot running leJOS.

As usual in a event-driven model, a callback function, here called stateChanged(state, msg) is invoked by the system, when an event is triggered. The Python library module is integrated into TigerJython, but can also be downloaded from this site to be used in a pure Python environment. The Java library module is distributed as JAR archive.

When the server is started, it creates a TCPServer object specifying the ports and the callback function onStateChanged() and embarks in the LISTENING state.

Python skeleton:

from tcpcom import TCPServer 
def onStateChanged(state, msg):
    ...

server = TCPServer(port, stateChanged = onStateChanged)


Java skeleton:

import ch.aplu.tcpcom.*;

TCPServer server = TCPServer(port);
server.addStateListener(this);

public void onStateChanged(String state, String msg)
{...}


The callback onStateChanged (state, msg) has two string parameters state and msg that describe the status change of the server:

state

msg

Description

TCPServer.LISTENING

port

An existing connection was terminated (or the server is started) and the server listens for a new connection

Server.PORT_IN_USE

port

The server cannot go into the LISTENING state because the port is occupied by another process

TCPServer.CONNECTED

client's IP address

A client has signed up and was accepted

TCPServer.MESSAGE

received message

The server has received a message

TCPSever.TERMINATED

(empty)

The server is terminated and does not  listen anymore

The client starts with the creation of a TCPClient object specifying the IP address of the server, the port and the callback function onStateChanged(). By invoking connect() it starts a connection trial.

Python skeleton:

from tcpcom import TCPClient
client = TCPClient(host, port, stateChanged = onStateChanged)
client.connect()


Java skeleton:

import ch.aplu.tcpcom.*;

TCPClient client = TCPClient(host, port);
client.addStateListener(this);

public void onStateChanged(String state, String msg)
{...}        


Again, the callback onStateChanged (state, msg) has two string parameters state and msg, describing the state change of the client:


state

msg

Description

TCPClient.CONNECTING

server's IP address:port

Starting connection attempt

TCPClient.CONNECTION_FAILED

server's IP address:port

Connection trial failed

TCPClient.SERVER_OCCUPIED

server's IP address:port

Connection trial failed because server is already connected

TCPClient.CONNECTED

server's IP address:port

Connection established

TCPClient.MESSAGE

received message

The server has received a message

TCPClient.DISCONNECTED

(empty)

Connection interrupted (aborted by client or server)

The call to connect() is blocking, which means that the function returns with True / true once the connection has succeeded, or with False / false after a certain timeout period (approximately 10 seconds) if the connection fails. The information about the success or failure of the connection can also be detected via the callback.

You can try out the client-server programs on the same PC by starting two TigerJython windows. In this case you choose the host address localhost. Using two different computers for the client and the server is more close to reality. They must be connected with a network cable or via wireless LAN and the link must be open for TCP/IP communication with the selected port. If the connection fails with your normal hotspot (WLAN access point), this is mostly due to firewall restrictions. In this case you can use your own router or start a mobile host spot app on your smartphone. Access of the mobile phone to the Internet is not necessary.

 

A First Glance: The Time-Server/Time-Client Scenario

To demonstrate how simple it is to write a client-server application using tcpcom, your first programming duty is to create a server that provides a time service. When a client logs on, it sends the current time (with date) back to the client. There are numerous such  time servers on the Internet and you can be proud that you are already in a position to code such a professional server application.

In order to turn off the time server, we use a well-known trick: The main program "hangs" in a modal message dialog opened by the blocking function. When the function returns by pressing the OK or clicking the close button, the server is stopped by calling terminate(). (In Python we use the easygui module that is much simpler than Tkinter. It can be downloaded from the Internet.)


Python server:

from easygui import msgbox
from tcpcom import TCPServer
import datetime

def onStateChanged(state, msg):
    print state, msg
    if state == TCPServer.CONNECTED:
        server.sendMessage(str(datetime.datetime.now()))

port = 5000
server = TCPServer(port, stateChanged = onStateChanged)
msgbox("Time Server running. OK to stop","Time Server")
server.terminate()

Python client:

from easygui import msgbox, enterbox
from tcpcom import TCPClient

def onStateChanged(state, msg):
    print state, msg
    if state == TCPClient.MESSAGE:
        client.disconnect()
        msgbox("Server reports local date/time: " + msg, title)
    elif state == TCPClient.CONNECTION_FAILED:
        msgbox("Server " + host + " not available", title)

title = "Time Client"
port = 5000

host= enterbox("Time Server IP Address?", title, "localhost", True)
if host != None:
    client = TCPClient(host, port, stateChanged = onStateChanged)
    client.connect()

In Java we use JOptionPane to create a modal message dialog. Unfortunately it is not so easy to catch or inhibit the close button click. So do not use it.

Java server:

import ch.aplu.tcpcom.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JOptionPane;

public class TimeServer implements TCPServerListener
{
  private TCPServer server;

  public TimeServer()
  {
    int port = 5000;
    server = new TCPServer(port);
    server.addTCPServerListener(this);
    // Do not click the title bar's close button
    JOptionPane.showMessageDialog(null, "Time Server running. OK to stop.",
      "Time Server", JOptionPane.INFORMATION_MESSAGE);
    server.terminate();
  }

  public void onStateChanged(String state, String msg)
  {
    System.out.println("State: " + state + "; Msg: " + msg);
    if (state.equals(TCPServer.CONNECTED))
    {
      DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
      Date date = new Date();
      server.sendMessage(dateFormat.format(date));
    }
  }

  public static void main(String[] args)
  {
    new TimeServer();
  }
}

Execute the program locally using WebStart

Java client:

import ch.aplu.tcpcom.*;
import javax.swing.JOptionPane;

public class TimeClient implements TCPClientListener
{
  private TCPClient client;
  private String host;

  public TimeClient()
  {
    int port = 5000;
    host = JOptionPane.showInputDialog("IPAddress", "localhost");
    if (host == null)
      return;
    client = new TCPClient(host, port);
    client.addTCPClientListener(this);
    client.connect();
  }

  public void onStateChanged(String state, String msg)
  {
    System.out.println("State: " + state + "; Msg: " + msg);
    if (state.equals(TCPClient.MESSAGE))
    {
      client.disconnect();
      JOptionPane.showMessageDialog(null,
        "Server reports local date/time: " + msg,
        "Time Client", JOptionPane.INFORMATION_MESSAGE);
    }
    else if (state.equals(TCPClient.CONNECTION_FAILED))
      JOptionPane.showMessageDialog(null,
        "Server " + host + " not available",
        "Time Client", JOptionPane.INFORMATION_MESSAGE);
  }

  public static void main(String[] args)
  {
    new TimeClient();
  }
}

Execute the program locally using WebStart