Home Work 6 - Networking in Java, C++, Python and VB using TCP

Document last modified: 



Overview Networking generally come in two flavors, datagram and connection-oriented, that is UDP (User Datagram Protocol) and TCP (Transport Control Protocol) respectively. Connection-oriented service generally operates with a client and server following the steps of 1) client requests connection to server, 2) server accepts connection, 3) bi-directional communication can occur through the connection, 4) either may close the connection. Most languages such as Java and VB support abstractions for the implementation of these necessary operations.

Example - The following are three examples of a client and server that uses TCP/IP related services. The client connects (a TCP service) to an echo server to send (a TCP service) and receive (a TCP service) an echo response from the server as in the figure at right. TCP service calls in each language are given below in bold. Note that the reality of TCP service implementation is never as neat as the abstraction, for example, it is not obvious whether the socket creation call  (underlined in the C++ example below) is a TCP or operating system service. One view that helps clarify the distinction is that the TCP services on one host should communicate with another host. The socket function is instead an operating system function that allocates resources on the local host only and does not communicate with another host. The C++ send function is obviously a TCP service since it literally sends data using the TCP connection from the client to the echo server.

Ports and Sockets - TCP identifies an application on a specific host by the host IP number and port number used by the application. For example, the main IUS Web server application is at www.ius.edu and port 80. The port number is the external reference to the application, that is the Web server application is referred to as port 80. Internal to the application the port number is mapped to a socket, the socket is used by the application to communicate over the TCP connection. This is illustrated in a typical configuration at right where the client has requested a connection on the server host through port 888. Once the connection is made the two host applications can communicate through the respective socket on each.

Protocol - For a client and server or peers to communicate, each must implement the appropriate protocols. The echo protocol is relatively simple and is stated below. In the client/server interaction, the client connects to the server and sends a message string such as Hi which the server receives and echos back the Hi to the client. The client indicates that communication is finished by closing the connection which the server receives and closes its end. To coordinate the connect and disconnect between the client and server a simple protocol is used between the two:

  1. the client requests a connection with the server,
  2. the server accepts the connection,
  3. the client sends "Hi" text for the server to echo,
  4. the server receives and echoes the string,
  5. the client receives echoed text,
  6. the client terminates the connection,
  7. the server terminates the connection.

It is important to note that any client or server following the protocol can be used interchangeably. The following provides examples of the protocol implementation in Java, C++, and Visual Basic.


Assignment


Turn In


Java

In the following examples, the communication between the client and server is implemented by corresponding function calls in each row of the table.
 

Client/Server Communication
Client Server
  ServerSocket connection = new ServerSocket( 888 );
Socket s = new Socket("localhost", 888 ); Socket s = connection.accept();
out.print(to); from=in.readLine( )
from=in.readLine( ) out.write(from);

Client and Server

// echoclient.java - Use: java -cp . echoclient <IP or DNS>

import java.net.*;
import java.io.*;

class echoclient {

 public static void main(String args[]) throws Exception {
   String to, from;
                                // Echo server IP and port
   Socket s = new Socket( 
        (args.length == 0) ? "localhost": args[0], 888 );
                                // Buffered socket input &output
   BufferedReader in = new BufferedReader(  
            new InputStreamReader(
                 s.getInputStream() ) );
   PrintStream out = new PrintStream(s.getOutputStream());
   BufferedReader keybd = new BufferedReader(  
            new InputStreamReader(System.in) );

   System.out.println("Blank line to end");
                                // Read keyboard and send
   while( (to=keybd.readLine()) != null && !to.equals("")) {
     out.print(to + "\r\n");    // to server until a blank line
     from=in.readLine();        // Wait for echo
     System.out.print( from );
   }
   s.close();                   // Close connection
 }
}
// echoserver.java Use: java -cp . echoserver

import java.net.*;
import java.io.*;

class echoserver {

 public static void main(String args[]) throws Exception {
   String from;

   ServerSocket connection = new ServerSocket( 888 );

                              // Wait for connection
   Socket s = connection.accept();
                              // Socket input & output  
   BufferedReader in = new BufferedReader(   
                         new InputStreamReader(
                           s.getInputStream() ) );
   PrintStream out = new PrintStream(s.getOutputStream());

   System.out.println("Connected"); 
                               // Echo client text till ""
   while( (from=in.readLine()) != null && !from.equals("")) {
     System.out.println( from );
     out.print(from + "\r\n"); // echo to client                     
   }
   s.close();                  // Close connection
   System.out.println("Disconnected");
 }
}

Use:

  1. Download the Java echo files.
  2. Open two Command Prompt windows.
  3. Compile in one window with:
  4. Execute the server and client in different windows by:
File Input - Java file input uses:

The following opens the file readfile.java and copies the contents to the console.
 

// readfile.java - Use: java -cp . readfile

 import java.io.*;


 class readfile {

    public static void main(String args[]) throws Exception {
       int ch;

       FileInputStream in = new FileInputStream("c:/temp/readfile.java");
       while( in.available() > 0 ) { 
           ch = in.read();
           System.out.print((char) ch);      
       }
       in.close();                                        
    }
 }

Parsing Client String - The path in the string GET /path HTTP/1.0 can be parsed by:

if (str != null && str.startsWith("GET /")) {        // Locate a string with GET / at start
    String p[] = str.split(" ");                            // Split into 3 strings, stored in array p,
                                                                   // p[0] = "GET", p[1] = "/path", p[2] = "HTTP/1.0".
}

Minimal HTTP server

When a connection is accepted on port 80, send HTTP reply and Hello World, then disconnect

import java.net.*;
import java.io.*;

class server {

 public static void main(String args[]) throws Exception {
    ServerSocket connection = new ServerSocket( 80 );
                         // Wait for connection
   Socket s = connection.accept();
                              // Socket output  
   PrintStream out = new PrintStream(s.getOutputStream());
                         // Send HTTP reply and Hello World
   out.print("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<H1>Hello world</H1>\r\n\r\n"); 
   s.close();        // Close connection
 }
}

Python

In the following examples, the communication between the client and server is implemented by corresponding function calls in each row of the table.

Client/Server Communication
Client Server
s = socket.socket(socket.AF_INET,
                          socket.SOCK_STREAM)
s = socket.socket(socket.AF_INET,
                          socket.SOCK_STREAM)
  s.bind((HOST, PORT))
  s.listen(1)
s.connect((HOST, PORT)) conn, addr = s.accept()
s.send('Hello world') data = conn.recv(1024)
data = s.recv(1024) conn.send(data)


  Client and Server

# echoclient.py

import socket, sys

HOST = sys.argv[1]        # The remote host
PORT = 8888                 # Port used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True :
   message = raw_input('Send:')
   if not message : break
   s.send(message)
   data = s.recv(1024)
   print 'Received', `data`
s.close()
# echoserver.py 

import socket

HOST = ''          # Symbolic name
PORT = 8888     # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while True:
    data = conn.recv(1024)
    if not data: break      # Client disconnected
    conn.send(data)
conn.close()
s.close()

Use:

  1. Copy the above into files named echoclient.py and echoserver.py.
  2. Open two Command Prompt windows.
  3. Execute the server and client in different windows by:
  4. Enter an empty line in echoclient to terminate

Receiving full lines

HTTP uses a blank line to terminate a message and all lines in the message are terminated by '\r\n' (carriage return and line feed characters). Because some clients (telnet) send a single character at a time while others (IE browser) send the complete message at once, you'll need to receive complete lines in order to accommodate both. For example, telnet sends GET as G, E, T but you'll find it simpler to collect all characters until receiving a full line terminated by '\r\n'.

The following recv's from a socket s until a line, anything terminated by '\r\n', is received. Note that this suffers from potential buffer over-run, a favorite attack point of hackers.

// recvLine.py 

import socket

HOST = ''          # Symbolic name
PORT = 8888     # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
From = ''
while True :
    data=conn.recv(1024)               # Read from client
    From=From+data
    if From.endswith( '\r\n' ) : break
print From
s.close()
conn.close()


File Input -
Python file input uses:

The following opens the file c:/temp/readfile.py and copies the contents to the console.
 

// readfile.py 

f = file('c:/temp/readfile.py')
while True :
   data = f.readline()
   if not data : break
   print data

Parsing Client String - The path in the string GET /path HTTP/1.0 can be parsed by:

p = 'GET /path HTTP/1.0'.split()       # Split into list of strings, stored in  p,
                                                   # p[0] = "GET", p[1] = "/path", p[2] = "HTTP/1.0".
 

Minimal HTTP server

When a connection is accepted on port 80, send HTTP reply and Hello World, then disconnect

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(1)

conn, addr = s.accept()
print conn.recv(1024)					# From client
							# To client
conn.send('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<H1>Hello world</H1>\r\n\r\n')

conn.close()
s.close()

C++ 

In the following examples, the communication between the client and server is implemented by corresponding function calls in each row of the table.
 

Client/Server Communication
Client Server
connect(s,(struct sockaddr*)&sin,sizeof(sin)) accept(s,(struct sockaddr*)&sin,&sinlen )
send(s,buffer,strlen(buffer)+1,0) recv(h,buffer,sizeof(buffer),0)
recv(s,buffer,sizeof(buffer),0) send(h,buffer,strlen(buffer)+1,0)

.NET and Visual Studio


Client

//      echoClient.cpp - Use: echoClient <IP> or <DNS>
//      Visual C++ Project | Settings | Link | Object/Library modules | ws2_32.lib 

#define WIN32_LEAN_AND_MEAN 
#include <winsock2.h> 
#include <iostream.h>

int main(int argc, char* argv[])              
{      char                       buffer[128]; 
        int                          retval; 
        unsigned int            addr=0; 
        struct sockaddr_in  sin; 
        struct hostent         *host; 
        WSADATA               wsaData; 
        SOCKET                  s; 
 
        WSAStartup(0x202,&wsaData);                         // Startup 
                                                                 
        host = gethostbyname(argv[1]);                       // Try DNS lookup

        if (!host)                                                            // DNS failed try as IP
                addr = inet_addr(argv[1]);  
        if ((!host)  && (addr == INADDR_NONE) ) {        // DNS and IP failed 
                cout << "Unable to resolve " << argv[1] << '\n'; 
                return -1; 
        }  
        if (host != NULL) {                                             // Copy server info 
                memcpy(&(sin.sin_addr),host->h_addr,host->h_length); 
                sin.sin_family = host->h_addrtype; 
        }
        else {
                sin.sin_addr.s_addr = addr; 
                sin.sin_family = AF_INET; 
        }
        sin.sin_port = htons(889);
                                                                                  // Create socket
        if ((s = socket(AF_INET, SOCK_STREAM,0)) == INVALID_SOCKET){  
                cout << "socket() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        }                                                                        // Connect to server port
        if (connect(s,(struct sockaddr*)&sin,sizeof(sin)) == INVALID_SOCKET) { 
                cout << "connect() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        } 
        
        send(s,"Hi",2,0);                                            // Send to echo server
        send(s,"\0",1,0);                                           // Send to echo server
        retval=recv(s,buffer,sizeof(buffer),0);                       
                                                                                // Receive echo from server
        while((retval=recv(s,buffer,sizeof(buffer),0) > 0) && buffer[0] != '\0') {   
                                                                                // 0 terminate buffer 
                if(retval < sizeof(buffer)) buffer[retval]='\0';   
                                                                                // print the echo 
                cout << "echoed " << buffer << "\n";   flush(cout);   
        } 
        closesocket(s);                                                // Close connection   
        cout << "Closed connection.\n"; flush(cout);
        return 0;
}

Server

//      echoServer.cpp - Use: echoServer
//      Visual C++ Project | Settings | Link | Object/Library modules | ws2_32.lib 

#define WIN32_LEAN_AND_MEAN 
#include <winsock2.h> 
#include <iostream.h>

int main(void)
{       char                         buffer[128]; 
        int                             retval, sinlen; 
        struct sockaddr_in     sin; 
        WSADATA                  wsaData; 
        SOCKET                     s, h; 

        WSAStartup(0x202,&wsaData); 
        sin.sin_family = AF_INET; 
        sin.sin_addr.s_addr = INADDR_ANY;
        sin.sin_port = htons(888);                                // Port 888
                                                                                // SOCK_STREAM is TCP
        if ((s = socket(AF_INET, SOCK_STREAM,0)) == INVALID_SOCKET){ 
                cout << "socket() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        }                                                                     // Bind socket to local port    
        if (bind(s,(struct sockaddr*)&sin,sizeof(sin) ) == SOCKET_ERROR) { 
                cout << "bind() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        }                                                                     // Listen for socket connection
        if (listen(s,1)== SOCK_ERROR) { 
                cout << "listen() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        } 
        sinlen = sizeof(sin); 
        
        while(1) {                                                       // Accept incoming connection   
          if ((h=accept(s,(struct sockaddr*)&sin,&sinlen )) == INVALID_SOCKET) { 
                cout << "accept() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
          } 
          cout << "Opened connection.\n";       flush(cout);
                                                                              // receive while connection open
          while((retval=recv(h,buffer,sizeof(buffer),0)) != SOCKET_ERROR && retval > 0){ 
                if(retval < sizeof(buffer))                         // Make into 0 terminated string
                        buffer[retval]='\0';
                cout << "Received " << buffer << "\n";   flush(cout); 
                                                                              // Echo what was received
                send(h,buffer,strlen(buffer)+1,0);
          } 
          closesocket(h);
          cout << "Closed connection.\n";       flush(cout);
        }
        return 0;
}


Visual Basic 6.0

In the following examples, the communication between the client and server is implemented by corresponding function calls in each row of the table.

Client/Server Communication
Client Server
echoClient.RemoteHost = "127.0.0.1"
echoClient.RemotePort = 888
echoClient.Connect
echoServer.LocalPort = 888
echoServer.Listen
echoServer.Accept requestID
echoClient.GetData strData echoServer.GetData strData
echoClient.SendData "echo " + txtOutput.Text echoServer.SendData strData

Client and Server

' Client

Private Sub Form_Load()
    ' The name of the Winsock control is echoClient.
    ' Note: to specify a remote host, you can use
    ' either the IP address (ex: "121.111.1.1") or name.
    echoClient.RemoteHost = "127.0.0.1"
    echoClient.RemotePort = 888
End Sub

Private Sub cmdDisconnect_Click() ' Disconnect 
    echoClient.Close
End Sub

Private Sub cmdSend_Click()     ' Send data to server
    echoClient.SendData txtOutput.Text
End Sub

Private Sub cmdConnect_Click() ' Connect to server
    If (echoClient.State <> sckClosed) Then
        echoClient.Close
    End If
    echoClient.Connect
End Sub

Private Sub echoClient_DataArrival(ByVal bytesTotal As Long)
' Display whatever is echoed back
    Dim strData As String
    echoClient.GetData strData
    txtOutput.Text = "echo " + strData
 End Sub

' Server

Private Sub Form_Load()
    ' Listen for connection on port 888'
    echoServer.LocalPort = 888
    echoServer.Listen
End Sub

Private Sub echoServer_Close()
    echoServer.Close
    echoServer.Listen
End Sub

Private Sub echoServer_ConnectionRequest(ByVal requestID As Long)
    ' Check if the control's State is closed. If not,
    ' close the connection before accepting the new connection.
    If echoServer.State <> sckClosed Then
        echoServer.Close
    End If
    ' Accept the request with the requestID parameter.
    echoServer.Accept requestID
End Sub

Private Sub echoServer_DataArrival(ByVal bytesTotal As Long)
    ' Echo received data
    Dim strData As String

    echoServer.GetData strData
    echoServer.SendData strData
End Sub

Controls

  • echoClient - WinSock
  • txtOutput - Text
  • cmdConnect - Command Button
  • cmdSend - Command Button
  • cmdDisconnect - Command Button

Controls

  • echoServer - WinSock

 

VB .Net

Networking in VB .Net can be much closer to C++. The following uses synchronized sockets, those that do not raise an event. Though simpler to understand, not practical without multithreading. The VB way is to use asynchronous sockets that raise an event whenever communication occurs on the connection.

Client/Server Communication
Client Server
Dim remoteEP As New _    
    IPEndPoint(Dns.Resolve("localhost").AddressList(0), 888)
Dim client As New Socket(AddressFamily.InterNetwork, _
    SocketType.Stream, ProtocolType.Tcp)
client.Connect(remoteEP)
Dim localEndPoint As _
     New IPEndPoint(Dns.Resolve("localhost").AddressList(0), 888)
Dim s As New Socket(AddressFamily.InterNetwork, _
     SocketType.Stream, ProtocolType.Tcp)
s.Bind(localEndPoint)
s.Listen(10)
Dim server As Socket = s.Accept()
client.Receive(bytes) server.Receive(bytes)
client.Send(msg) server.Send(bytes)

Client and Server

' Client
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text

Public Class echoClient

  Public Shared Sub Start()
    Dim bytes(1024) As Byte ' Data buffer for incoming data.

    Try ' Connect to a remote device.
       ' Establish the remote endpoint for the socket.
       Dim remoteEP As New _    
          IPEndPoint(Dns.Resolve("localhost").AddressList(0), 888)
       ' Create a TCP/IP socket.
       Dim client As New Socket(AddressFamily.InterNetwork, _
              SocketType.Stream, ProtocolType.Tcp)

       Try ' Connect the socket to the remote endpoint.
         client.Connect(remoteEP)

         Console.WriteLine("Socket connected to {0}", _
             client.RemoteEndPoint.ToString())

         ' Encode the data string into a byte array.
         Dim msg As Byte() = _
            Encoding.ASCII.GetBytes("Testing<EOF>")

         ' Send the data through the socket.
         Dim bytesSent As Integer = client.Send(msg)

         ' Receive the response from the remote device.
         Dim bytesRec As Integer = client.Receive(bytes)
         Console.WriteLine("Echoed test = {0}", _
            Encoding.ASCII.GetString(bytes, 0, bytesRec))

         ' Release the socket.
         client.Shutdown(SocketShutdown.Both)
         client.Close()
      Catch e As Exception
        Console.WriteLine(e.ToString())
      End Try

    Catch e As Exception
       Console.WriteLine(e.ToString())
    End Try
  End Sub
End Class

Module Module1
Sub Main()
Dim echoclient As New echoClient()
echoclient.Start()
End Sub
End Module
 
' Server
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic

Public Class echoServer
  Public Shared receivedData As String = Nothing

  Public Shared Sub Start()
  Dim bytes() As Byte = New [Byte](1024) {} 

  ' Establish the local endpoint for the socket.
  Dim localEndPoint As _
          New IPEndPoint(Dns.Resolve("localhost").AddressList(0), 888)

  ' Create a TCP/IP socket.
  Dim s As New Socket(AddressFamily.InterNetwork, _
                SocketType.Stream, ProtocolType.Tcp)

  Try ' Bind socket to the local endpoint, listen for incoming connections.
    s.Bind(localEndPoint)
    s.Listen(10)

    While True ' Start listening for connections.
      Console.WriteLine("Waiting for a connection...")
      Dim server As Socket = s.Accept()
      receivedData = ""

      ' An incoming connection needs to be processed.
      Do Until receivedData.IndexOf("<EOF>") > -1
        bytes = New Byte(1024) {}
        Dim msg As Integer = server.Receive(bytes)
        receivedData += Encoding.ASCII.GetString(bytes, 0, msg)
        Console.WriteLine("Text received : {0}", receivedData)
        server.Send(bytes)
      Loop

      ' Echo the data back to the client.
      server.Shutdown(SocketShutdown.Both)
      server.Close()
    End While

   Catch e As Exception
      Console.WriteLine(e.ToString())
   End Try
  End Sub
End Class

Module Module1
  Sub Main()
    Dim echoserver As New echoServer()
    echoserver.Start()
  End Sub
End Module

Java Connection Services 

A key advantage of Java for network applications is the relative simplicity of communication using datagram (User Datagram Protocol) and connection services (Transport Control Protocol). The primary advantage of connection-oriented services is input and output can be treated as a stream of reliable data, much as reading or writing a file. The following discusses the key parts of Java for using networking services.

Port - A workstation is uniquely identified by its IP number such as 149.160.51.113 associated with an NIC but may be communicating with multiple sites. To maintain each communication separately datagrams are sent and received through unique ports. A few applications, such as SMTP (port 25), HTTP (port 80), FTP, etc. have well-known port numbers that are generally reserved. IN our example, we used one port (888) and receive through one bi-directional port. It is important to note that the sender port number must match the receiver port number.

Socket - A connection socket provides a reliable, bi-directional communication path between two applications. Two types of socket can be created, server and client with the key difference that server sockets wait for a connection while client sockets initiate connections.

Client - Socket s = new Socket("www.abc.com", 888); creates a client socket that attempts a connection to a server www.abc.com on port 888. If the connection is unavailable an error condition results.

Server - ServerSocket c = new ServerSocket( 888); creates a server socket that listens on port 888 but does not accept a connection from a client. Socket sc = c.accept(); waits for a connection via the server socket returning a regular connection socket.

Communication - Applications can perform input and output over a connection exactly as with any I/O stream from file, console, etc. such as read on InputStream, write on OutputStream objects, and print on PrintStream objects..

Input - InputStream in = sc.getInputStream(); int c = in.read(); reads an integer (which could be cast to a character, etc.) from the connection on socket sc.

Often simplest to use buffered input. BufferedReader class for input supports input of a complete string or individual characters and has the following useful characteristics:

Output - Easiest to use is:

PrintStream out = new PrintStream( sc.getOutputStream );
out.print("Hello");

would write an "Hello" to the connection on socket sc. PrintStream objects can output strings, numbers, etc.

InetAddress - The IP address representation of a system. InetAddress(getLocalHost())returns the address of the machine executing the statement.

File Input - Java file input uses:

The following opens the file readfile.java and copies the contents to the console.
 

// readfile.java - Use: java -cp . readfile

 import java.io.*;


 class readfile {

    public static void main(String args[]) throws Exception {
       int ch;

       FileInputStream in = new FileInputStream("c:/temp/readfile.java");
       while( in.available() > 0 ) { 
           ch = in.read();
           System.out.print((char) ch);      
       }
       in.close();                                        
    }
 }

Parsing Client String - The path in the string GET /path HTTP/1.0 can be parsed by:

if (str != null && str.startsWith("GET /")) {        // Locate a string with GET / at start
    String p[] = str.split(" ");                            // Split into 3 strings, stored in array p,
                                                                   // p[0] = "GET", p[1] = "/path", p[2] = "HTTP/1.0".
}


C++ Connection Services

Visual C++ supports TCP/IP services through Windows Sockets and requires that the ws2_32.lib library be linked to the executeable. To add the library in Visual C++ enter:

 

Project | Settings | Link | Object/Library modules | ws2_32.lib

Port - Same concept as Java. In our example, the server used one port (888). The server must bind the port and socket, the client would not normally bind a specific port.

        sin.sin_port = htons(888);              // Port 888
                                                // SOCK_STREAM is TCP
        if ((s = socket(AF_INET, SOCK_STREAM,0)) == INVALID_SOCKET){ 
                cout << "socket() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        } 
                                               // Bind socket to local port    
        if (bind(s,(struct sockaddr*)&sin,sizeof(sin) ) == SOCKET_ERROR) { 
                cout << "bind() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        }

Socket - The TCP socket is created as SOCK_STREAM. Sockets are the same for  server and client, the key difference is use, the server listens for connections on sockets while client sockets initiate connections.

Client -  Connects to a server port.

      if (connect(s,(struct sockaddr*)&sin,sizeof(sin)) == INVALID_SOCKET) { 
                cout << "connect() failed with error " << WSAGetLastError() << '\n'; 
                return -1; 
        }

Server - Listens for connections and waits to accept a connection from a client.

        lister(s,1); 
        sinlen = sizeof(sin); 
        h=accept(s,(struct sockaddr*)&sin,&sinlen );

Input - recv(h, buffer, sizeof(buffer), 0); Blocks for data on socket h and fill buffer with up to the size of buffer characters.

Output - send(h, buffer, strlen(buffer)+1 ,0); Sends buffer through the socket h.

gethostbyname - gethostbyname("www.ius.edu"); Returns the hostent structure information.

inet_addr - inet_addr("149.160.16.200"); Converts an IPv4 number to address appropriate for in_addr structure.

File Input - Use:

The following prints the file readfile.java to the console.

#include <fstream.h>  
#include <iostream.h>

void main(void) {  
        fstream in; 
        char ch; 

        in.open( "c:\\temp\\readfile.java", ios::in); 

        while ( !in.eof() ) { 
                in.get(ch); 
                cout << ch;
        } 
        in.close(); 
} 

Visual Basic 6.0 Connection Services

Visual Basic implements connection services (Transport Control Protocol) using a tool named Winsock, Windows Sockets, which has the same capabilities as Java. The following discusses the key parts of VB for using networking services that differ from the Java discussion.

One key distinction is that VB uses graphical tools, the tool for Winsock appears as . Since it is not normally on the toolbar, it must be placed there by:

  1. Click on Project menu and select Components.
  2. Select the Microsoft Winsock Component

The component can then be placed on a form that uses Winsock objects.

Client -     echoClient.RemoteHost = "www.abc.com"
                  echoClient.RemotePort = 888
                  echoClient.Connect

creates a client socket that attempts a connection to a server www.abc.com on port 888. If the connection is unavailable an error condition results.

Server -      echoServer.LocalPort = 888
                    echoServer.Listen

creates a server socket that listens on port 888 to accept a connection from a client.

The server must implement a procedure that is executed when a connection is requested. It is supplied the ID of the machine making the request as in the following:

                    Private Sub echoServer_ConnectionRequest(ByVal requestID As Long)
                       echoServer.Accept requestID
                    End Sub

Input - When data arrives on a connection an event occurs to execute the DataArrival procedure.

        Sub echoServer_DataArrival(ByVal bytesTotal As Long)
            Dim strData as string
                echoServer.GetData strData
            End Sub

reads a string from the connection.

Output - Send data out the connection by:

                echoServer.SendData "Hello"

Closing - When the connection is finished both side should close the connection by:

                echoServer.Close

File Input - Use:

The following prints the file readfile.java to a picture object when clicked.

Sub Picture1_Click()
Dim line As String
Open "c:\temp\readfile.java" For Input As #1

While (Not EOF(1))
    Input #1, line
    Picture1.Print line
Wend
Close #1
End Sub


Threaded Servers

Each of the echo server implementations could manage only a single connection at a time but real servers must be capable of handling multiple simultaneous connections. The solution most often used is to perform the operation of a single server by a single thread of execution. Each client connection causes a new server to be started to service that connection alone and each connection close causes its server to be terminated.

The following is a Java implementation of a threaded echo server that can support an arbitrary number of simultaneous client connections. Java language includes very straightforward mechanisms that make implementing threaded servers relatively simple. In the following example note that lines 18-32 are copied from the single connection server implemented above. The remaining lines create and start a thread for each connection. One important programming element necessary for threading is the ability to create a set of resources for exclusive use by each thread. In the example, each serverThread is an object with independent data created by:

new serverThread(s);

The serverThread class inherits from class Runnable basic thread operations. The statement:

new Thread(this).start( );

calls the run( ) function to start the thread execution. The thread executes within the run( ) function until the client closes the connection. When the run( ) function is exited, the thread terminates.

Note that threads are supported by libraries in C++. Visual Basic supports threads and event driven method execution, for a good discussion of Visual Basic threading see http://www.desaware.com/articles/threadingL3.htm.
 

threadedEchoServer.java
  1. // threadedEchoServer.java - Multiple simultaneous connections to Port 888
  2. //  Use: java -cp . threadedEchoServer
  3. import java.net.*;
  4. import java.io.*;
  5. class serverThread implements Runnable
  6. {  Socket s;
  7.    public serverThread(Socket s) throws Exception
  8.    {    this.s = s; 
  9.          new Thread(this).start();        // Start thread
  10.    }
  11.    public void run() 
  12.    { 
  13.       String from;
  14.       try {                                              // Socket input and output   
  15.         BufferedReader in = new BufferedReader( 
  16.                                 new InputStreamReader(
  17.                                     s.getInputStream() ) );
  18.         PrintStream out = new PrintStream(s.getOutputStream());
  19.  
  20.         while(  (from=in.readLine()) != null && !from.equals("")) {
  21.           System.out.print( from );
  22.           out.print(from); 
  23.         }
  24.         s.close();                                       // Close connection
  25.       } catch (Exception e) { System.out.println("in Close error"); }
  26.    }
  27. }
     
  28. public class threadedEchoServer
  29. {
  30.         public static void main(String args[]) throws Exception
  31.         {                                                  // Port 888 is echo
  32.                 ServerSocket connection = new ServerSocket( 888 ); 
  33.                 while(true)                           // Wait for connection
  34.                 {       Socket s = connection.accept();
  35.                          System.out.println("Connection");
  36.                          new serverThread(s);  // Start new echoServer thread
  37.                 }
  38.         }
  39. }

Use:

  1. Download the Java echo files.
  2. Open three Command Prompt windows.
  3. Compile in one window with:
  4. Execute the server and client in different windows (same directory) by:


Command/Response Client/Server

Most client/server configurations interact in a command/response mode where the client sends a command and the server returns a response with the interaction characterized by the client and server taking turns. One example is a Web browser and server. A simple example is given below of a racing game where the client takes turns with server moving on a grid, each attempting to crash into the other first. While the command/response interaction model is relatively simple to program it is inappropriate where high interactivity is required, as is this case where either the client or server should be able to make multiple moves without waiting on the other to move. Instead each are forced to take turns making a move, first the client then the server, the interaction is obvious in the following code fragments.

Client
  1.   do {
  2.     sender.send();          // Send client move
  3.     receiver.receive();   // Receive server move 
  4. } while(!race.over()); 
Server
  1. do { 
  2.     receiver.receive();    // Receive client move
  3.     sender.send();           // Send server move
  4. } while(!race.over()); 

A description of the racing game following the command/response model.

Problem - When racing the client and server must alternate moves because each alternates calls to the send and receive methods.

Question

Turn taking Racer
// Racerserver.java - Use: java -cp . Racerserver

import java.net.*;
import java.io.*;

public class Racerserver {
        
  public static void main(String args[]) throws Exception {
                                                    // Server IP and port
    ServerSocket connection = new ServerSocket( 888 );
              
    Socket s = connection.accept();                      // Wait for connection
 
    BufferedReader in = new BufferedReader(         // Buffered socket input and output
                                       new InputStreamReader( s.getInputStream() ) );
    PrintStream out = new PrintStream(s.getOutputStream());

    Race race = new Race('S', 2, 2, 'C', 0, 0);       // Start race
    Receiver receiver = new Receiver(in, race);
    Sender sender = new Sender(out, race);

    do {
        receiver.receive();                                   // Receive client move
        sender.send();                                         // Send server move
    } while(!race.over());          
    s.close();                                                       // Close connection
  }
}
// Racerclient.java - Use: java -cp . Racerclient <IP or DNS>

import java.net.*;
import java.io.*;

public class Racerclient {
        
  public static void main(String args[]) throws Exception {
                                                                          // Server IP and port
    Socket s = new Socket( (args.length == 0) ? "localhost" : args[0], 888 );  

    BufferedReader in = new BufferedReader(        // Buffered socket input and output
                            new InputStreamReader( s.getInputStream() ) );
    PrintStream out = new PrintStream(s.getOutputStream());

    Race race = new Race('C', 0, 0, 'S', 2, 2);      // Start of race
    Receiver receiver = new Receiver(in, race);
    Sender sender = new Sender(out, race);

    do {
        sender.send();                                        // Send client move
        receiver.receive();                                  // Receive server move
    } while(!race.over());          
    s.close();                                                      // Close connection
  }
}
// Sender.java
import java.net.*;
import java.io.*;

class Sender {
        PrintStream out;
        Race race;

        public Sender(PrintStream out, Race race) {
                this.out = out;
                this.race = race;
        }

        public void send() {
                char c='\0';
                try {   
                  do {
                          if(System.in.available() > 0) {
                                 c=(char) System.in.read();
                                 switch(c) {
                                        case 'I': case 'J': case 'K': case 'M': 
                                             out.print(c);
                                             race.moveme(c);
                                 }
                          }
                  } while (c != 'I' && c != 'J' && c != 'K' && c != 'M' && !race.over());
                }
                catch(Exception e) { }
        }
}
// Receiver.java
import java.net.*;
import java.io.*;

class Receiver {

        BufferedReader in;
        Race race;

        public Receiver(BufferedReader in, Race race) { 
                this.in = in; 
                this.race = race;
        }

        public void receive() {
                char c;
                try {   
                        c = (char) in.read(); 
                        switch(c) {
                                case 'I': case 'J': case 'K': case 'M': 
                                        race.movethem(c);
                        }
                }
                catch(Exception e) {}   
        }
}

Use:

  1. Download the  Java Command/Response Client/Server files.
  2. Open two Command Prompt windows.
  3. Compile in one window with:
  4. Execute the server and client in different windows by:
  5. Alternate from client to server window with moves.


Threaded Client/Server

The primary difference between this and the previous example is that racers move at any time, no turn taking required. The turn taking was necessary because reading a connection-oriented stream blocks execution until there are characters to read. Once the read of the connection-oriented stream starts to await the client racer's move there is no way to unblock to read the server move from the keyboard. There are ways around this problem such as checking the number of available characters before attempting to read the stream. However, the problem can be more simply solved by using two threads, one for reading the connection-oriented stream and another for reading the keyboard. Whichever move is read first is applied to the race.

Threaded Racer
// RacerThreadedServer.java - Use: java -cp . Racerserver

import java.net.*;
import java.io.*;

public class RacerThreadedServer {
        
  public static void main(String args[]) throws Exception {
                                                    // Server IP and port
    ServerSocket connection = new ServerSocket( 888 );
                
    Socket s = connection.accept();                 // Wait for connection
 
    BufferedReader in = new BufferedReader(         // Buffered socket I/O
                             new InputStreamReader( s.getInputStream() ) );
    PrintStream out = new PrintStream(s.getOutputStream());

    Race race = new Race('S', 2, 2, 'C', 0, 0);     // Start race
    ReceiverThread receiver = new ReceiverThread(in, race);
    SenderThread sender = new SenderThread(out, race);
  }
}
// RacerThreadedClient.java - Use: java -cp . Racerclient <IP or DNS>

import java.net.*;
import java.io.*;

public class RacerThreadedClient {
        
  public static void main(String args[]) throws Exception {
                                                    // Server IP and port
    Socket s = new Socket( (args.length == 0) ? "localhost" : args[0], 888 );  

    BufferedReader in = new BufferedReader(         // Buffered socket I/O
                            new InputStreamReader( s.getInputStream() ) );
    PrintStream out = new PrintStream(s.getOutputStream());

    Race race = new Race('C', 0, 0, 'S', 2, 2);     // Start of race
    ReceiverThread receiver = new ReceiverThread(in, race);
    SenderThread sender = new SenderThread(out, race);
  }
}
// SenderThread.java

import java.net.*;
import java.io.*;

class SenderThread implements Runnable {
  PrintStream out;
  Race race;

  public SenderThread(PrintStream out, Race race) {
    this.out = out;
    this.race = race;
    new Thread(this).start();
  }

  public void run() {
    while(!race.over()) send();
    out.close();
  }

  public void send() {
    char c;

    try {   if(System.in.available() > 0) {
               c=(char) System.in.read();
               switch(c) {
                  case 'I': case 'J': case 'K': case 'M': 
                            out.print(c);
                            race.moveme(c);
               }
             }
    }
    catch(Exception e) { }
  }
}
// ReceiverThread.java

import java.net.*;
import java.io.*;

class ReceiverThread implements Runnable {
  BufferedReader in;
  Race race;

  public ReceiverThread(BufferedReader in, Race race) { 
     this.in = in; 
     this.race = race;
     new Thread(this).start();
  }

  public void run() {
     while(!race.over()) receive();
  }

  public void receive() {
     char c;
     try {   c = (char) in.read(); 
             switch(c) {
                case 'I': case 'J': case 'K': case 'M': 
                     race.movethem(c);
             }
     }
     catch(Exception e) { }          
  }
}

Use:

  1. Download the Java Threaded Client/Server files.
  2. Open two Command Prompt windows.
  3. Compile in one window with:
  4. Execute the server and client in different windows by:
  5. Use either client to server window for moves. No need to alternate.




Race - The Race class implements a racing game where two opponents attempt to crash into the other. Each racer moves in one of four directions from an initial starting position. The game state is represented as a position on a 20x20 grid for each of two racers. A single character is printed on the 20x20 grid for each player after each move until a collision. The racer causing the collision is declared the winner.

Note the use of synchronized for the moveme and movethem methods. The effect is when either of the methods is calls, a exclusive access lock is placed on the instance data of the Race object. If the moveme method is being executed, the movethem method is forced to wait until moveme method completes. Because the program using two threads, the ReceiverThread which calls movethem and SenderThread which calls moveme. Since common data is modified in both methods, it is possible for each method to corrupt the modifications of the other. Exclusive access of the Race object by each method prevents this form of data corruption. This is sometimes called serialization since the threads that normally execute in parallel are forced into serial execution when accessing common data.

Race.java
class Race {
   int xme, yme, xthem, ythem;
   char me, them;
   char winner;

   public Race(char me, int xme, int yme, char them, int xthem, int ythem) { 
      this.me = me;           this.xme = xme;         this.yme = yme;
      this.them = them;     this.xthem = xthem;   this.ythem = ythem;
      winner='?';
      System.out.print("Keys\n I\nJ K\n M\n");
      print();
   }

   public void print() {
      for(int y=0; y < 20; y++) {
         for(int x=0; x<20; x++) 
            if (x==xme && y==yme) System.out.print(me); 
            else if (x==xthem && y==ythem) System.out.print(them);
                 else System.out.print('.');
         System.out.println();
      }
      if(over()) System.out.println(winner + " wins");
      System.out.println();
   }
        
   public synchronized void moveme(char direction) {
      switch (direction) {
         case 'I' : if (yme > 0)  yme--; break;
         case 'J' : if (xme > 0)  xme--; break;
         case 'K' : if (xme < 19) xme++; break;
         case 'M' : if (yme < 19) yme++; break;
      }
      if(xme == xthem && yme == ythem) { winner = me; them = '*'; me = '*'; }
      print();
    }

    public synchronized void movethem(char direction) {
       switch (direction) {
          case 'I' : if (ythem > 0)  ythem--; break;
          case 'J' : if (xthem > 0)  xthem--; break;
          case 'K' : if (xthem < 19) xthem++; break;
          case 'M' : if (ythem < 19) ythem++; break;
       }
       if(xme == xthem && yme == ythem) { winner = them; them = '*'; me = '*';}
       print();
    }

    public boolean over() {
       return winner != '?';
    }
}

State

Computers are examples of state machines. State machines are simple machines that:

Maintaining state in a program is generally critical to performing useful work. For example, the following requires that variable A keep its value or state between transition from the state when A = 4 to the new state where A = A + 1:

A = 4
A = A + 1

Servers may maintain state of a client or not between messages. HTTP servers typically are termed stateless because each file request from a browser is treated independently from any previous request. The server receives and processs a request from the browser for a file download and forgets about the browser request immediately after outputting the file.

The Racer game is an example of a stateful server which must keep track of the state of the race game as the position of each player on the 20x20 grid. The race state is maintained by the Race object. It is important to note that the client/server are connected for the duration of the race and the Race object exists to maintain race state for the duration of the connection.

Multiple Connection Server

Maintaining state for a server is relatively straightforward when only a single client connection must be handled at a time. When multiple client connections must be handled simultaneously, care must be taken that the state of each client connection is maintained separately. The following example illustrates a race server that can support an arbitary number of race clients, note that the client programs remain unchanged. The key to maintaining separate state for each client is to create a set of new objects for each client connection so that each client has its own set of data.

The new server supports multiple client connections, maintaining the state of each race in separate objects for:

The server waits for a client connection at the connection.accept( ) statement. When a client connection is made the objects necessary for the race state are created. A very important point is that new threads are started for handling each new client connection independent of all other clients. Not only does each client have separate objects for maintaining state, each client also has separate threads for handling the connection input and output. The server maintains two separate connections with two clients in the figure at right.
 

MultiConnectionRaceServer.java
// MultiConnectionRaceServer.java - Use: java -cp . MultiConnectionRaceServer

import java.net.*;
import java.io.*;

public class MultiConnectionRaceServer {
        
  public static void main(String args[]) throws Exception {
                                                                              // Server IP and port
    ServerSocket connection = new ServerSocket( 888 );

    while (true) {                                   
      Socket s = connection.accept();                       // Wait for connection
 
      BufferedReader in = new BufferedReader(         // Buffered socket input and output
                              new InputStreamReader( s.getInputStream() ) );
      PrintStream out = new PrintStream(s.getOutputStream());

      Race race = new Race('S', 2, 2, 'C', 0, 0);        // Start race
      ReceiverThread receiver = new ReceiverThread(in, race);
      SenderThread sender = new SenderThread(out, race);
    }
  }
}

Use:

  1. Download the Java Multiple Connection Server files.
  2. Open three Command Prompt windows.
  3. Compile in one window with:
  4. Execute the server and client in different windows by:
  5. Use either client to server window for moves. No need to alternate.

Files

The following files may be downloaded by clicking on the name:


Document last modified: