CS865 – Distributed Software Development

The Socket API

 

Based on:

·        M.L. Liu, Distributed Computing: Principles and Applications, Addison-Wesley, 2004, ISBN-10: 0201796449

·        Java Sockets 101 – PDF

Also See:

·       http://java.sun.com/docs/books/tutorial/networking/sockets/index.html

 

Introduction

 

Socket Definition:

Bruce Eckel (Thinking in Java):

The socket is the software abstraction used to represent the "terminals" of a connection between two machines.

For a given connection, there's a socket on each machine, and you can imagine a hypothetical "cable" running between the two machines with each end of the "cable" plugged into a socket.

Of course, the physical hardware and cabling between machines is completely unknown.

The whole point of the abstraction is that we don't have to know more than is necessary.

 

•The socket API is an Interprocessing Communication (IPC) programming interface originally provided as part of the Berkeley UNIX operating system.

De facto standard for programming IPC - the basis of more sophisticated IPC interface such as remote procedure call and remote method invocation.

 

The conceptual model of the socket API

 

 

The socket API

·       A socket API provides a programming construct termed a socket. 

·       A process wishing to communicate with another process must create an instance, or instantiate, such a construct

·       The two processes then issues operations provided by the API to send and receive data.

 

 

Connection-oriented & connectionless datagram socket

A socket programming construct can make use of either the UDP or TCP protocol. 

·        Sockets that use UDP for transport are known as datagram sockets

·        Sockets that use TCP are termed stream sockets.

 

·        TCP sockets (implemented by the Java Socket class)

·        UDP sockets (implemented by the Java DatagramSocket class)

o       Datagram sockets can support both connectionless and connection-oriented communication at the application layer.

 

TCP and UDP play the same role, but do it differently

·        Both receive transport protocol packets and pass along their contents to the Presentation Layer.

·        TCP divides messages into packets (datagrams) and reassembles them in the correct sequence at the receiving end.

o       It also handles requesting retransmission of missing packets.

o       With TCP, the upper-level layers have much less to worry about.

·        UDP doesn't provide assembly and retransmission requesting features.

o       It simply passes packets along.

o       The upper layers have to make sure that the message is complete and assembled in correct sequence.

 

 

The Java Datagram Socket API

In Java, two classes are provided for the datagram socket API:

1.    the DatagramSocket class for the sockets.

2.    the DatagramPacket class for the datagram exchanged.

·        A process wishing to send or receive data using this API must instantiate a DatagramSocket object, or a socket in short.  

·        Each socket is said to be bound to a UDP port of the machine local to the process

To send a datagram to another process, a process:

·        creates an object that represents the datagram itself. 

·        This object can be created by  instantiating a DatagramPacket object which carries

1.    the payload data as a reference to a byte array, and

2.    the destination address (the host ID and port number to which the receiver’s socket is bound.

·        issues a call to a send method in the DatagramSocket object, specifying a reference to the DatagramPacket object as an argument

 

 

Receiving process - a DatagramSocket object:

·        must be instantiated and bound to a local port

·        the port number must agree with that specified in the datagram packet of the sender. 

·        the receive process creates a datagramPacket object which references a byte array and calls a receive method in its DatagramSocket object, specifying as argument a reference to the DatagramPacket object. 

 

The Data Structures in the sender and receiver programs

 

 

The program flow in the sender and receiver programs

 

 

Connectionless sockets

·        Possible for multiple processes to simultaneously send datagrams to the same socket established by a receiving process

·        The order of the arrival of these messages will be unpredictable, in accordance with the UDP protocol

 

 

 

 

 

Setting timeout

·        To avoid indefinite blocking, a timeout can be set with a socket object:

void setSoTimeout(int timeout)

·        Set a timeout for the blocking receive from this socket, in milliseconds.

·        Once set, the timeout will be in effect for all blocking operations.

 

Key Methods and Constructors

 

The coding

 

Event synchronization with the connectionlss datagram socketsAPI

 

 

 

Example 1: One-way communication between two process

Example1Sender.java

import java.net.*;

import java.io.*;

 

/**

 * This example illustrates the basic method calls for connectionless

 * datagram socket.

 * @author M. L. Liu

 */

 

public class Example1Sender {

// An application which sends a message using connectionless

// datagram socket.

// Three command line arguments are expected, in order:

//    <domain name or IP address of the receiver>

//    <port number of the receiver's socket>

//    <message, a string, to send>

  

public static void main(String[] args) {

      if (args.length != 3)

         System.out.println

            ("This program requires three command line arguments");

      else {

         try {

                InetAddress receiverHost = InetAddress.getByName(args[0]);

                int receiverPort = Integer.parseInt(args[1]);

            String message = args[2];

    

            // instantiates a datagram socket for sending the data

           DatagramSocket    mySocket = new DatagramSocket();          

            byte[ ] buffer = message.getBytes( );                                     

            DatagramPacket datagram =

               new DatagramPacket(buffer, buffer.length,

                                  receiverHost, receiverPort);

            mySocket.send(datagram);

            mySocket.close( );

         } // end try

      catch (Exception ex) {

       ex.printStackTrace( );

      }

      } // end else

   } // end main

} // end class

 

Example1Receiver.java

import java.net.*;

import java.io.*;

 

/**

 * This example illustrates the basic method calls for connectionless

 * datagram socket.

 * @author M. L. Liu

 */

 

public class Example1Receiver {

 

// An application which receives a message using connectionless

// datagram socket.

// A command line argument is expected, in order:

//    <port number of the receiver's socket>

// Note: the same port number should be specified in the

// command-line arguments for the sender.

 

   public static void main(String[] args) {

      if (args.length != 1)

         System.out.println

            ("This program requires a command line argument.");

      else {

              int port = Integer.parseInt(args[0]);

         final int MAX_LEN = 10;

            // This is the assumed maximum byte length of the

            //      datagram to be received.

              try {

           DatagramSocket    mySocket = new DatagramSocket(port); 

               // instantiates a datagram socket for receiving the data

            byte[ ] buffer = new byte[MAX_LEN];                                    

            DatagramPacket datagram =

               new DatagramPacket(buffer, MAX_LEN);

            mySocket.receive(datagram);

            String message = new String(buffer);

            System.out.println(message);

            mySocket.close( );

         } // end try

      catch (Exception ex) {

        ex.printStackTrace( );

      }

      } // end else

   } // end main

} // end class

 

Example 2: Two-way communication between two process

·       Example1Sender must bind its socket to a specific address so Example1Receiver can send data datagrams to that address.

·        MyDatagramSocket.java is created as a subclass of DatagramSocket with two instances for sending and receiving messages.

·        Example2SenderReceiver program instantiates a MyDatagramSocket object then calls its sendMessage method followed by a call to receiveMessage.

·        Example2ReceiverSender instantiates a MyDatagramSocket object then calls its receiveMessage method followed by a call to sendMessage.

 

MyDatagramSocket.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 MyDatagramSocket extends DatagramSocket {

   static final int MAX_LEN = 100; 

   MyDatagramSocket(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

 

Example2SenderReceiver.java

import java.net.*;

 

/**

 * This example illustrates a process which sends then receives

 * using a datagram socket.

 * @author M. L. Liu

 */

public class Example2SenderReceiver {

 

// An application which sends then receives a message using

// connectionless datagram socket.

// Four command line arguments are expected, in order:

//    <domain name or IP address of the receiver>

//    <port number of the receiver's datagram socket>

//    <port number of this process's datagram socket>

//    <message, a string, to send>

 

   public static void main(String[] args) {

      if (args.length != 4)

         System.out.println

            ("This program requires four command line arguments");

      else {

         try {     

                InetAddress receiverHost = InetAddress.getByName(args[0]);

            int receiverPort = Integer.parseInt(args[1]);

                int myPort = Integer.parseInt(args[2]);

            String message = args[3];

           MyDatagramSocket mySocket = new MyDatagramSocket(myPort); 

               // instantiates a datagram socket for both sending

               // and receiving data

            mySocket.sendMessage( receiverHost, receiverPort, message);

                   // now wait to receive a datagram from the socket

            System.out.println(mySocket.receiveMessage());

                   mySocket.close( );

         } // end try

           catch (Exception ex) {

            ex.printStackTrace( );

           } //end catch

      } //end else

   } //end main

 

} //end class

 

Example2ReceiverSender.java

import java.net.*;

 

/**

 * This example illustrates a process which sends then receives

 * using a datagram socket.

 * @author M. L. Liu

 */

public class Example2ReceiverSender {

 

// An application which sends then receives a message using

// connectionless datagram socket.

// Four command line arguments are expected, in order:

//    <domain name or IP address of the receiver>

//    <port number of the receiver's datagram socket>

//    <port number of this process's datagram socket>

//    <message, a string, to send>

 

   public static void main(String[] args) {

      if (args.length != 4)

         System.out.println

            ("This program requires four command line arguments");

      else {

         try {     

                InetAddress receiverHost = InetAddress.getByName(args[0]);

            int receiverPort = Integer.parseInt(args[1]);

                int myPort = Integer.parseInt(args[2]);

            String message = args[3];

           MyDatagramSocket mySocket = new MyDatagramSocket(myPort); 

               // instantiates a datagram socket for both sending

               // and receiving data

                   // First wait to receive a datagram from the socket

            System.out.println(mySocket.receiveMessage());

                // Now send a message to the other process.

            mySocket.sendMessage( receiverHost, receiverPort, message);

                   mySocket.close( );

         } // end try

           catch (Exception ex) {

            ex.printStackTrace( );

           } //end catch

      } //end else

   } //end main

 

} //end class

 

 

The Stream-mode Socket API

·       The datagram socket API supports the exchange of discrete units of data (that is, datagrams).

·       The stream socket API provides a model of data transfer based on the stream-mode I/O of the Unix operating systems. 

·       By definition, a stream-mode socket supports connection-oriented communication only.

 

 

Stream-mode Socket API (connection-oriented socket API)

 

 

Stream-mode Socket API

·       A stream-mode socket is established for data exchange between two specific processes.

·       Data stream is written to the socket at one end, and read from the other end.

·       A stream socket cannot be used to communicate with more than one process.

 

Java stream-mode socket API is provided with two classes:

·        Server socket: for accepting connections; we will call an object of this class a connection socket.

·        Socket: for data exchange; we will call an object of this class a data socket.

 

The server (the connection listener)

 

 

Key methods in the ServerSocket class

Note: Accept is a blocking operation.

 

 

Key methods in the Socket class

A read operation on the InputStream is blocking.

A write operation is nonblocking.

 

Stream-mode Socket API program flow

 

 

Example: Stream Mode Sockets

 

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(String 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

 

   public void close( )

          throws IOException {   

      socket.close( );

   }

} //end class

 

Example5ConnectionAcceptor.java

import java.net.*;

import java.io.*;

 

/**

 * This example illustrates the basic syntax for stream-mode

 * socket.

 * @author M. L. Liu

 */

 

public class Example5ConnectionAcceptor {

 

// An application which receives a message using stream-mode socket

// Two command line arguments are expected, in order:

//    <port number for the the Server socket used in this process>

//    <message, a string, to send>

 

   public static void main(String[] args) {

      if (args.length != 2)

         System.out.println

            ("This program requires three command line arguments");

      else {

         try {

                int portNo = Integer.parseInt(args[0]);

            String message = args[1];

            // instantiates a socket for accepting connection     

           ServerSocket connectionSocket = new ServerSocket(portNo);

/**/        System.out.println("now ready accept a connection"); 

            // wait to accept a connecion request, at which

            //  time a data socket is created                 

            MyStreamSocket dataSocket = 

               new MyStreamSocket(connectionSocket.accept());

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

            dataSocket.sendMessage(message);

 

/**/        System.out.println("message sent");

            dataSocket.close( );

/**/        System.out.println("data socket closed");

            connectionSocket.close( );

/**/        System.out.println("connection socket closed");

         } // end try

           catch (Exception ex) {

           ex.printStackTrace( );

           } // end catch

      } // end else

   } // end main

} // end class

 

Example5ConnectionRequestor.java

import java.net.*;

import java.io.*;

 

/**

 * This example illustrates the basic syntax for stream-mode

 * socket.

 * @author M. L. Liu

 */

 

public class Example5ConnectionRequestor {

 

// An application that sends a message using stream-mode socket.

// Two command line arguments are expected:

//

//    <host name of the connection accceptor>

//    <port number of the connection accceptor>

 

   public static void main(String[] args) {

      if (args.length != 2)

         System.out.println

            ("This program requires two command line arguments");

      else {

         try {

            String acceptorHost = args[0];

                int acceptorPort = Integer.parseInt(args[1]);

            // instantiates a data socket

           MyStreamSocket mySocket =

               new MyStreamSocket(acceptorHost, acceptorPort);

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

            String message = mySocket.receiveMessage( );

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

            System.out.println("\t" + message);

            mySocket.close( );

/**/        System.out.println("data socket closed");

         } // end try

           catch (Exception ex) {

            ex.printStackTrace( );

           }

      } // end else

   } // end main

} // end class

 

 

Event Diagram for Stream Mode Sockets

 

 

 

Secure Sockets

http://java.sun.com/products/jsse/

·        Secure sockets perform encryption on the data transmitted.

·        The JavaTM Secure Socket Extension (JSSE) is a Java package that enables secure Internet communications.

·        It implements a Java version of SSL (Secure Sockets Layer) and TLS (Transport Layer Security) protocols

·        It includes functionalities for data encryption, server authentication, message integrity, and optional client authentication.

·        Using JSSE, developers can provide for the secure passage of data between a client and a server running any application protocol.

 

The Java Secure Socket Extension API

http://java.sun.com/products/jsse/doc/apidoc/index.html

Import javax.net.ssl;

·        Class SSLServerSocket is a subclass of ServerSocket, and inherits all its methods.

·        Class SSLSocket is a subclass of Socket, and inherits all its methods.

·        There are also classes for

Certification

Handshaking

KeyManager

SSLsession