The Socket API 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: //
// // 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: // // 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: // // // // 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: // // // // 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: // // 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: // // // 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