CS865 – Distributed Software Development

The Client-Server Model

 

Based on:

 

Introduction

·        The Client-Server paradigm is the most prevalent model for distributed computing protocols.

·        It is the basis of all distributed computing paradigms at a higher level of abstraction.

·        It is service-oriented, and employs a request-response protocol.

 

The Client-Server Paradigm

·        A server process, running on a server host, provides access to a service.

·        A client process, running on a client host, accesses the service via the server process.

·        The interaction of the process proceeds according to a protocol.

 

 

Client-server applications and services

·        An application based on the client-server paradigm is a client-server application.

·        On the Internet, many services are Client-server applications.  These services are often known by the protocol that the application implements.

·        Well known Internet services include HTTP, FTP, DNS, finger, gopher, etc.

·        User applications may also be built using the client-server paradigm.

 

 

Client-server system architecture vs. Client-server distributed computing

·        Client-server system architecture - terms clients and servers refer to computers,

·        Client-server distributed computing paradigm - terms refer to processes.

 

 

Client-server, an overloaded term

 

 

A protocol/service session

·        Session - the interaction between the server and one client.

·        Service managed by a server may be accessed by multiple clients who desire the service, sometimes concurrently. 

·        Each client, when serviced by the server, engages in a separate session with the server, during which it conducts a dialog with the server until the client has obtained the service it required

 

A service session

 

 

The Protocol for a Network Service

·        Protocol required to specify the rules that must be observed by the client and the server during the conduction of a service.  

·        Rules include specifications on matters such as :

(i)                how the service is to be located,

(ii)              the sequence of interprocess communication,

(iii)            the representation and interpretation of data exchanged with each IPC.

·        On the Internet, such protocols are specified in the RFCs (Requests for Coments).

 

 

Locating the service

·        A mechanism must be available to allow a client process to locate a server for a given service. 

·        A service can be located through the address of the server process, in terms of the host name and protocol port number assigned to the server process.  

·        This is the scheme for Internet services. 

·        Each Internet service is assigned to a specific port number. 

·        A well-known service such as ftp, HTTP, or telnet is assigned a default port number reserved on each Internet host for that service. 

·        At a higher level of abstraction, a service may be identified using a logical name registered with a registry,

·        The logical name will need to be mapped to the physical location of the server process. 

·        If the mapping is performed at runtime (that is, when a client process is run), then it is possible for the service’s location to be dynamic, or moveable.

 

 

Implementation of a network service

·        Must adhere to the specification for the protocol, including how the dialogs of each session should proceed.  

·        The specification defines

(i)                which side (client or server) should speak first

(ii)              the syntax and semantic of each request and response

(iii)            the action expected of each side upon receiving a particular request or response.

 

 

Interprocess communications (IPC) and event synchronization

The interaction of the client and server processes follows a request-response pattern.

 

Session IPC examples

·        The dialog in each session follows a pattern prescribed in the protocol specified for the service.

·        e.g. Daytime service [RFC867]:

Client:

Hello, <client address> here.  May I have a timestamp please.

Server:

Here it is: (time stamp follows) World Wide Web session:

Client:

Hello,  <client address> here. 

Server:

Okay.  I am a web server and speaks protocol HTTP1.0.

Client:

Great, please get  me the web page index.html at the root of your document tree.

Server:

Okay, here’s what’s in the page: (contents follows).

 

The getAddress and getPort Methods

 

Client-server protocol data representation

Part of the specification of a protocol is the syntax and semantics of each request and response.

·        The choice of data representation depends on the nature and the needs of the protocol.

·        Representing data using text (character strings) is common, as it facilitates data marshalling and allows the data to be readable by human.

·        Most well known Internet protocols are client-server, request-response, and text-base.

 

 

Example: Daytime Client-server using Connectionless Datagram Socket

 

UML class diagram for DaytimeClient1

 

Client-side Presentation logic

DaytimeClient1.java encapsulates the client-side presentation logic; that is, it provides the interface for a user of the client process. 

·        Code in this class is concerned with obtaining input (the server address) from the user, and displaying the output (the timestamp) to the user. 

·        To obtain the timestamp, a method call to a “helper” class, DaytimeClientHelper1.java, is issued.   

·        This method hides the details of the application logic and the underlying service logic. 

o       The programmer of DaytimeClient1.java need not be aware of which socket types is used for the IPC.

import java.io.*;

 

 

/**

 * This module contains the presentaton logic of a DaytimeClient.

 * @author M. L. Liu

 */

 

public class DaytimeClient1 {

   public static void main(String[] args) {

      InputStreamReader is = new InputStreamReader(System.in);

      BufferedReader br = new BufferedReader(is);

      try {

         System.out.println("Welcome to the Daytime client.\n" +

                            "What is the name of the server host?");

         String hostName = br.readLine();

         if (hostName.length() == 0) // if user did not enter a name

            hostName = "localhost";  //   use the default host name

         System.out.println("What is the port number of the server host?");

         String portNum = br.readLine();

         if (portNum.length() == 0)

            portNum = "13";          // default port number

         System.out.println("Here is the timestamp received from the server"

                             + DaytimeClientHelper1.getTimestamp(hostName, portNum));

      } // end try 

      catch (Exception ex) {

         ex.printStackTrace( );

      } // end catch

   } //end main

} // end class

 

Client-side Application logic

DaytimeClientHelper1.java  encapsulates the client-side application logic. 

·        Performs the IPC for sending a request and receiving a response, using a specialized class of the DatagramSocket => myClientDatagramSocket. 

o       Note:

§        the details of using datagram sockets are hidden from this module. 

§        this module does not need to deal with the byte array for carrying the payload data.

import java.net.*;

 

/**

 * This class is a module which provides that application logic

 * for a Daytime Client.

 * @author M. L. Liu

 */

 

public class DaytimeClientHelper1 {

 

   public static String getTimestamp(String hostName, String portNum){ 

  

      String timestamp = "";

      try {     

              InetAddress serverHost = InetAddress.getByName(hostName);

              int serverPort = Integer.parseInt(portNum);

          // instantiates a datagram socket for both sending

          // and receiving data

         MyDatagramSocket mySocket = new MyDatagramSocket(); 

          mySocket.sendMessage( serverHost, serverPort, "");

           // now receive the timestamp

          timestamp = mySocket.receiveMessage();

         mySocket.close( );

 

       } // end try

      catch (Exception ex) {

         System.out.println("There is a problem: " + ex);

      }

       return timestamp;

   } //end getTimeStamp

} //end class 

 

Service logic

MyClientDatagramSocket.java

·        provides the details of the IPC service using the datagram socket API.

import java.net.*;

import java.io.*;

 

/**

 * A subclass of DatagramSocket which contains

 * methods for sending and receiving messages

 * @author M. L. Liu

 */

 

public class MyClientDatagramSocket extends DatagramSocket {

static final int MAX_LEN = 100; 

   MyClientDatagramSocket( ) throws SocketException{

     super( );

   }

   MyClientDatagramSocket(int portNo) throws SocketException{

     super(portNo);

   }

   public void sendMessage(InetAddress receiverHost,

                           int receiverPort,

                           String message)

                    throws IOException {   

         byte[ ] sendBuffer = message.getBytes( );                                    

         DatagramPacket datagram =

            new DatagramPacket(sendBuffer, sendBuffer.length,

                                  receiverHost, receiverPort);

         this.send(datagram);

   } // end sendMessage

 

   public String receiveMessage()

     throws IOException {        

         byte[ ] receiveBuffer = new byte[MAX_LEN];

         DatagramPacket datagram =

            new DatagramPacket(receiveBuffer, MAX_LEN);

         this.receive(datagram);

         String message = new String(receiveBuffer);

         return message;

   } //end receiveMessage

} //end class

 

 

Server-side software

 

UML Diagram for the Datagram Daytime server

 

 Presentation logic

·        Typically, there is very little presentation logic on the server-side. 

·        In this case, the only user input is for the server port, which, for simplicity, is handled using a command-line argument.

 

Application logic

DaytimeServer1.java class encapsulates the server-side application logic. 

·        This module executes in a forever loop, waiting for a request form a client and then conduct a service session for that client.  

·        The module performs the IPC for receiving a request and sending a response, using a specialized class of the DatagramSocket, myServerDatagramSocket. 

·        Note

o       the details of using datagram sockets are hidden from this module.

o       In particular, this module does not need to deal with the byte array for carrying the payload data. 

 

Service logic

    The MyServerDatagram.java class provides the details of the IPC service, in this case using the datagram socket API. 

 

DaytimeServer1.java

import java.io.*;

import java.util.Date;   // for obtaining a timestamp

 

/**

 * This module contains the application logic of a Daytime server

 * which uses a connection datagram socket for interprocess communication.

 * A command-line argument is required to specify the server port.

 * @author M. L. Liu

 */

 

public class DaytimeServer1 {

   public static void main(String[] args) {

      int serverPort = 13;    // default port

      if (args.length == 1 )

         serverPort = Integer.parseInt(args[0]);      

      try {

         // instantiates a datagram socket for both sending

         // and receiving data

        MyServerDatagramSocket mySocket = new MyServerDatagramSocket(serverPort);

         System.out.println("Daytime server ready."); 

         while (true) {  // forever loop

            DatagramMessage request = mySocket.receiveMessageAndSender();

            System.out.println("Request received");

            // The message received is unimportant; it is the sender's

            // address that we need in order to reply.

                 // Now obtain the timestamp from the local system.

            Date timestamp = new Date ();

            System.out.println("timestamp sent: "+ timestamp.toString());

            // Now send the reply to the requestor

            mySocket.sendMessage(request.getAddress( ),

                       request.getPort( ), timestamp.toString( ));

             } //end while

       } // end try

         catch (Exception ex) {

         System.out.println("There is a problem: " + ex);

         } // end catch

   } //end main

} // end class 

 

MyServerDatagramSocket.java

import java.net.*;

import java.io.*;

 

/**

 * A subclass of DatagramSocket which contains

 * methods for sending and receiving messages

 * @author M. L. Liu

 */

 

public class MyServerDatagramSocket extends DatagramSocket {

static final int MAX_LEN = 100;

   MyServerDatagramSocket(int portNo) throws SocketException{

     super(portNo);

   }

   public void sendMessage(InetAddress receiverHost,

                           int receiverPort,

                           String message)

                    throws IOException {   

         byte[ ] sendBuffer = message.getBytes( );                                    

         DatagramPacket datagram =

            new DatagramPacket(sendBuffer, sendBuffer.length,

                                  receiverHost, receiverPort);

         this.send(datagram);

   } // end sendMessage

 

   public String receiveMessage( )

          throws IOException {        

         byte[ ] receiveBuffer = new byte[MAX_LEN];

         DatagramPacket datagram =

            new DatagramPacket(receiveBuffer, MAX_LEN);

         this.receive(datagram);

         String message = new String(receiveBuffer);

         return message;

   } //end receiveMessage

 

   public DatagramMessage receiveMessageAndSender( )

          throws IOException {        

         byte[ ] receiveBuffer = new byte[MAX_LEN];

         DatagramPacket datagram =

            new DatagramPacket(receiveBuffer, MAX_LEN);

         this.receive(datagram);

         // create a DatagramMessage object, to contain message

         //   received and sender's address

         DatagramMessage returnVal = new DatagramMessage( );

         returnVal.putVal(new String(receiveBuffer),

                          datagram.getAddress( ),

                          datagram.getPort( ));

         return returnVal;

   } //end receiveMessage

} //end class

 

DatagramMessage.java

import java.net.*;

/**

 * A class to use with MyServerDatagramSocket for

 * returning a message and the sender's address

 * @author M. L. Liu

 */

public class DatagramMessage{

   private String message;

   private InetAddress senderAddress;

   private int senderPort;

   public void putVal(String message, InetAddress addr, int port) {

      this.message = message;

      this.senderAddress = addr;

      this.senderPort = port;

   }

 

   public String getMessage( ) {

      return this.message;

   }

 

   public InetAddress getAddress( ) {

      return this.senderAddress;

   }

 

   public int getPort( ) {

      return this.senderPort;

   }

} // end class 

 

 

The Client-Server Model

 

Connectionless server vs. connection-oriented server

A connectionless server

·        Uses a connectionless IPC API (e.g., connectionless datagram socket)

·        Sessions with concurrent clients can be interleaved.

A connection-oriented server

·        Uses a connection-oriented IPC API (e.g. stream-mode socket )

·        Sessions with concurrent clients can only be sequential unless the server is threaded

 

Example: Connectionless EchoServer 1

·        An echo server is a server that echoes back whatever it receives from a client.

·        For example, if a client sends the server the string Hello there! the server will respond with the exact data it received from the client -  Hello there!

 

EchoServer1.java

·        Forever Looping

·        Server reads line from socket and then writes the line back to the socket addressing reply to sender

·        Since there is no connection, server can interact with many clients interleaving messages

import java.io.*;

 

/**

 * This module contains the application logic of an echo server

 * which uses a connectionless datagram socket for interprocess

 * communication.

 * A command-line argument is required to specify the server port.

 * @author M. L. Liu

 */

 

public class EchoServer1 {

   public static void main(String[] args) {

      int serverPort = 7;    // default port

      if (args.length == 1 )

         serverPort = Integer.parseInt(args[0]);      

      try {

         // instantiates a datagram socket for both sending

         // and receiving data

        MyServerDatagramSocket mySocket = new MyServerDatagramSocket(serverPort);

         System.out.println("Echo server ready."); 

         while (true) {  // forever loop

            DatagramMessage request =

               mySocket.receiveMessageAndSender();

            System.out.println("Request received");

            String message = request.getMessage( );

            System.out.println("message received: "+ message);

            // Now send the echo to the requestor

            mySocket.sendMessage(request.getAddress( ),

               request.getPort( ), message);

             } //end while

       } // end try

         catch (Exception ex) {

          ex.printStackTrace( );

         } // end catch

   } //end main

} // end class     

 

EchoClient1.java

import java.io.*;

 

/**

 * This module contains the presentaton logic of an Echo Client.

 * @author M. L. Liu

 */

 

public class EchoClient1 {

   static final String endMessage = ".";

   public static void main(String[] args) {

      InputStreamReader is = new InputStreamReader(System.in);

      BufferedReader br = new BufferedReader(is);

      try {

         System.out.println("Welcome to the Echo client.\n" +

                            "What is the name of the server host?");

         String hostName = br.readLine();

         if (hostName.length() == 0) // if user did not enter a name

            hostName = "localhost";  //   use the default host name

         System.out.println("What is the port number of the server host?");

         String portNum = br.readLine();

         if (portNum.length() == 0)

            portNum = "7";          // default port number

         EchoClientHelper1 helper =

            new EchoClientHelper1(hostName, portNum);

         boolean done = false;

         String message, echo;

         while (!done) {

            System.out.println("Enter a line to receive an echo back from the server, "

                            + "or a single peroid to quit.");

            message = br.readLine( );

            if ((message.trim()).equals (endMessage)){

               done = true;

               helper.done( );

            }

            else {

               echo = helper.getEcho( message);

               System.out.println(echo);

            }

          } // end while

      } // end try 

      catch (Exception ex) {

         ex.printStackTrace( );

      } // end catch

   } //end main

} // end class      

 

EchoClientHelper1.java

import java.net.*;

import java.io.*;

 

/**

 * This class is a module which provides the application logic

 * for an Echo client using connectionless datagram socket.

 * @author M. L. Liu

 */

 

public class EchoClientHelper1 {

   private MyClientDatagramSocket mySocket;

   private InetAddress serverHost;

   private int serverPort;

 

   EchoClientHelper1(String hostName, String portNum)

      throws SocketException, UnknownHostException {

        this.serverHost = InetAddress.getByName(hostName);

          this.serverPort = Integer.parseInt(portNum);

      // instantiates a datagram socket for both sending

      // and receiving data

     this.mySocket = new MyClientDatagramSocket();

   }

    

   public String getEcho( String message)

      throws SocketException, IOException {                                                                                

      String echo = "";   

      mySocket.sendMessage( serverHost, serverPort, message);

        // now receive the echo

      echo = mySocket.receiveMessage();

      return echo;

   } //end getEcho

 

   public void done( ) throws SocketException {

      mySocket.close( );

   }  //end done

 

} //end class

 

Concurrent client sessions with EchoServer1

 

 

Example: Connection-oriented EchoServer 2 – Iterative Server

·        Uses stream-mode socket API

·        No Overlapping of Sessions

 

Two consecutive client sessions with echo server2

 

EchoServer2.java

import java.io.*;

import java.net.*;

 

/**

 * This module contains the application logic of an echo server

 * which uses a stream socket for interprocess  communication.

 * A command-line argument is required to specify the server port.

 * @author M. L. Liu

 */

 

public class EchoServer2 {

   static final String endMessage = ".";

 

   public static void main(String[] args) {

      int serverPort = 7;    // default port

      String message;

 

      if (args.length == 1 )

         serverPort = Integer.parseInt(args[0]);      

      try {

         // instantiates a stream socket for accepting

         //   connections

        ServerSocket myConnectionSocket =

            new ServerSocket(serverPort);

/**/     System.out.println("Daytime server ready."); 

         while (true) {  // forever loop

            // wait to accept a connection

/**/        System.out.println("Waiting for a connection.");

            MyStreamSocket myDataSocket = new MyStreamSocket

                (myConnectionSocket.accept( ));

/**/        System.out.println("connection accepted");

            boolean done = false;

            while (!done) {

               message = myDataSocket.receiveMessage( );

/**/           System.out.println("message received: "+ message);

               if ((message.trim()).equals (endMessage)){

                  //Session over; close the data socket.

/**/              System.out.println("Session over.");

                  myDataSocket.close( );

                  done = true;

               } //end if

               else {

                  // Now send the echo to the requestor

                  myDataSocket.sendMessage(message);

               } //end else

                 } //end while !done

         } //end while forever

       } // end try

         catch (Exception ex) {

          ex.printStackTrace( );

         }

   } //end main

} // end class

 

MyStreamSocket.java

import java.net.*;

import java.io.*;

 

/**

 * A wrapper class of Socket which contains

 * methods for sending and receiving messages

 * @author M. L. Liu

 */

 

public class MyStreamSocket extends Socket {

   private Socket  socket;

   private BufferedReader input;

   private PrintWriter output;

 

   MyStreamSocket(InetAddress acceptorHost, int acceptorPort ) throws

     SocketException,IOException{

      socket = new Socket(acceptorHost, acceptorPort );

      setStreams( );

 

   }

 

   MyStreamSocket(Socket socket)  throws IOException {

      this.socket = socket;

      setStreams( );

   }

 

   private void setStreams( ) throws IOException{

      // get an input stream for reading from the data socket

      InputStream inStream = socket.getInputStream();

      input =

         new BufferedReader(new InputStreamReader(inStream));

      OutputStream outStream = socket.getOutputStream();

      // create a PrinterWriter object for character-mode output

      output =

         new PrintWriter(new OutputStreamWriter(outStream));

   }

 

   public void sendMessage(String message)

                    throws IOException {   

      output.println(message);  

      //The ensuing flush method call is necessary for the data to

      // be written to the socket data stream before the

      // socket is closed.

      output.flush();              

   } // end sendMessage

 

   public String receiveMessage( )

          throws IOException {   

      // read a line from the data stream

      String message = input.readLine( ); 

      return message;

   } //end receiveMessage

 

} //end class

 

EchoClient2.java

import java.io.*;

 

/**

 * This module contains the presentaton logic of an Echo Client.

 * @author M. L. Liu

 */

 

public class EchoClient2 {

   static final String endMessage = ".";

 

   public static void main(String[] args) {

      InputStreamReader is = new InputStreamReader(System.in);

      BufferedReader br = new BufferedReader(is);

      try {

         System.out.println("Welcome to the Echo client.\n" +

            "What is the name of the server host?");

         String hostName = br.readLine();

         if (hostName.length() == 0) // if user did not enter a name

            hostName = "localhost";  //   use the default host name

         System.out.println("What is the port number of the server host?");

         String portNum = br.readLine();

         if (portNum.length() == 0)

            portNum = "7";          // default port number

         EchoClientHelper2 helper =

            new EchoClientHelper2(hostName, portNum);

         boolean done = false;

         String message, echo;

         while (!done) {

            System.out.println("Enter a line to receive an echo "

               + "from the server, or a single period to quit.");

            message = br.readLine( );

            if ((message.trim()).equals (endMessage)){

               done = true;

               helper.done( );

            }

            else {

               echo = helper.getEcho( message);

               System.out.println(echo);

            }

          } // end while

      } // end try 

      catch (Exception ex) {

         ex.printStackTrace( );

      } //end catch

   } //end main

} // end class

 

EchoClientHelper2.java

import java.net.*;

import java.io.*;

 

/**

 * This class is a module which provides the application logic

 * for an Echo client using stream-mode socket.

 * @author M. L. Liu

 */

 

public class EchoClientHelper2 {

 

   static final String endMessage = ".";

   private MyStreamSocket mySocket;

   private InetAddress serverHost;

   private int serverPort;

 

   EchoClientHelper2(String hostName,String portNum)

         throws SocketException, UnknownHostException, IOException {

         this.serverHost = InetAddress.getByName(hostName);

          this.serverPort = Integer.parseInt(portNum);

      //Instantiates a stream-mode socket and wait for a connection.

     this.mySocket = new MyStreamSocket(this.serverHost,

         this.serverPort);

/**/  System.out.println("Connection request made");

   } // end constructor

    

   public String getEcho( String message) throws SocketException,

      IOException{    

      String echo = "";   

      mySocket.sendMessage( message);

        // now receive the echo

      echo = mySocket.receiveMessage();

      return echo;

   } // end getEcho

 

   public void done( ) throws SocketException,

                              IOException{

      mySocket.sendMessage(endMessage);

      mySocket.close( );

   } // end done

} //end class

 

 
Iterative servers vs. Concurrent servers

n   A connection-oriented server can be threaded so that it can service multiple clients concurrently.  Such a server is said to be a concurrent server.

n   An unthreaded connection-oriented server is said to be an iterative server.

 

A Concurrent, Connection-oriented Server

 

 

Example: Concurrent Server - EchoServer 3

·        Client-side unchanged – can use EchoClient2

 

Sequence diagram – EchoServer3

 

EchoServer3.java

import java.io.*;

import java.net.*;

 

/**

 * This module contains the application logic of an echo server

 * which uses a stream-mode socket for interprocess communication.

 * Unlike EchoServer2, this server services clients concurrently.

 * A command-line argument is required to specify the server port.

 * @author M. L. Liu

 */

 

public class EchoServer3 {

 

   public static void main(String[] args) {

      int serverPort = 7;    // default port

      String message;

 

      if (args.length == 1 )

         serverPort = Integer.parseInt(args[0]);      

      try {

         // instantiates a stream socket for accepting

         //   connections

        ServerSocket myConnectionSocket =

            new ServerSocket(serverPort);

/**/     System.out.println("Echo server ready."); 

         while (true) {  // forever loop

            // wait to accept a connection

/**/        System.out.println("Waiting for a connection.");

            MyStreamSocket myDataSocket = new MyStreamSocket

                (myConnectionSocket.accept( ));

/**/        System.out.println("connection accepted");

            // Start a thread to handle this client's sesson

            Thread theThread =

               new Thread(new EchoServerThread(myDataSocket));

            theThread.start();

            // and go on to the next client

            } //end while forever

       } // end try

         catch (Exception ex) {

          ex.printStackTrace( );

         } // end catch

   } //end main

} // end class

 

EchoServerThread.java

import java.io.*;

/**

 * This module is to be used with a concurrent Echo server.

 * Its run method carries out the logic of a client session.

 * @author M. L. Liu

 */

 

class EchoServerThread implements Runnable {

   static final String endMessage = ".";

   MyStreamSocket myDataSocket;

 

   EchoServerThread(MyStreamSocket myDataSocket) {

      this.myDataSocket = myDataSocket;

   }

 

   public void run( ) {

      boolean done = false;

      String message;

      try {

         while (!done) {

             message = myDataSocket.receiveMessage( );

/**/         System.out.println("message received: "+ message);

             if ((message.trim()).equals (endMessage)){

                //Session over; close the data socket.

/**/            System.out.println("Session over.");

                myDataSocket.close( );

                done = true;

             } //end if

             else {

                // Now send the echo to the requestor

                myDataSocket.sendMessage(message);

             } //end else

          } //end while !done

        }// end try

        catch (Exception ex) {

           System.out.println("Exception caught in thread: " + ex);

        } // end catch

   } //end run

} //end class

 

 

Echo3Server concurrent sessions

 

 

Server Thread class  template

class ServerThread implements Runnable {

   static final String endMessage = ".";

   MyStreamSocket myDataSocket;

   ServerThread(MyStreamSocket myDataSocket) {

      this.myDataSocket = myDataSocket;

   }

   public void run( ) {

      boolean done = false;

      String message;

      try {

        //add code here

      }// end try

      catch (Exception ex) {

           System.out.println("Exception caught in thread: " + ex);

      }

   } //end run

} //end class

 

 

Stateful servers vs. Stateless servers

 

Stateful server

·        A stateful server maintain stateful information on each active client. 

·        Stateful information can reduce the data exchanged, and thereby the response time.

e.g Stateless vs Stateful server

 

 

Issues

Stateful vs. Stateless server

·        Stateless server is straightforward to code.

·        Stateful server is harder to code, but the state information maintained by the server can reduce the data exchanged, and allows enhancements to a basic service.

·        Maintaining stateful information is difficult in the presence of failures.

 

Example: Stateful Server

·        A counter protocol is implemented that increments a counter by one each time the server is contacted by a client and send it back to the client.

 

CounterServer1.java

import java.io.*;

 

/**

 * This module contains the application logic of a Counter server

 * which uses a  datagram socket for interprocess communication.

 * A command-line argument is required to specify the server port.

 * @author M. L. Liu

 */

 

public class CounterServer1 {

 

   /* state information */

   static int counter = 0;

 

   public static void main(String[] args) {

      int serverPort = 12345;    // default port

      if (args.length == 1 )

         serverPort = Integer.parseInt(args[0]);      

      try {

         // instantiates a datagram socket for both sending

         // and receiving data

        MyServerDatagramSocket mySocket =

            new MyServerDatagramSocket(serverPort);

/**/     System.out.println("Counter server ready."); 

         while (true) {  // forever loop

            DatagramMessage request =

               mySocket.receiveMessageAndSender();

            System.out.println("Request received");

            // The message received is unimportant; it is the sender's

            // address that we need in order to reply.

                 // Now increment the counter, then send its value to the client.

            increment( );

/**/        System.out.println("counter sent: "+ counter);

            // Now send the reply to the requestor

            mySocket.sendMessage(request.getAddress( ),

               request.getPort( ), String.valueOf(counter));

             } //end while

       } // end try

         catch (Exception ex) {

          ex.printStackTrace( );

         }

   } //end main

 

   static private synchronized void increment( ){

       counter++;   

   }

 

} // end class     

 

CounterClient1.java

import java.io.*;

 

/**

 * This module contains the presentation logic of a counter Client.

 * @author M. L. Liu

 */

 

public class CounterClient1 {

   public static void main(String[] args) {

      InputStreamReader is = new InputStreamReader(System.in);

      BufferedReader br = new BufferedReader(is);

      try {

         System.out.println("Welcome to the Counter client.\n" +

                            "What is the name of the server host?");

         String hostName = br.readLine();

         if (hostName.length() == 0) // if user did not enter a name

            hostName = "localhost";  //   use the default host name

         System.out.println("Enter the port # of the server host:");

         String portNum = br.readLine();

         if (portNum.length() == 0)

            portNum = "12345";       // default port number

         System.out.println

            ("Here is the counter received from the server: "

             + CounterClientHelper1.getCounter(hostName, portNum));

      } // end try 

      catch (Exception ex) {

         ex.printStackTrace( );

      } // end catch

   } //end main

} // end class    

 

CounterClientHelper1.java

import java.net.*;

 

/**

 * This class is a module which provides the application logic

 * for a Counter Client.

 * @author M. L. Liu

 */

 

public class CounterClientHelper1 {

    

   public static int getCounter(String hostName,

      String portNum){  

 

      int counter = 0;

      String message = "";

      try {     

              InetAddress serverHost =

             InetAddress.getByName(hostName);

              int serverPort = Integer.parseInt(portNum);

          // instantiates a datagram socket for both sending

          // and receiving data

         MyDatagramSocket mySocket = new MyDatagramSocket(); 

          mySocket.sendMessage( serverHost, serverPort, "");

               // now receive the timestamp

          message = mySocket.receiveMessage();

/**/      System.out.println("Message received: " + message);

          counter = Integer.parseInt(message.trim());

              mySocket.close( );

       } // end try

         catch (Exception ex) {

          ex.printStackTrace( );

         } // end catch

       return counter;

   } //end main

} //end class