Socket Programming with UDP

Socket Programming with UDP

We studied in the previous section that when two processes communicate over TCP, it is as if there were a pipe between the two processes. This pipe remains in place until one of the two processes closes it. When one of the processes wants to send some bytes to the other process, it simply inserts the bytes into the pipe. The sending process does not have to attach a destination address to the bytes because the pipe is logically connected to the destination. Moreover, the pipe provides a reliable byte-stream channel - the sequence of bytes received by the receiving process is precisely the sequence of bytes that the sender inserted into the pipe.

UDP also allows two (or more) processes running on different hosts to communicate. On the other hand, UDP differs from TCP in various fundamental ways. First, UDP is a connectionless service - there isn't an initial handshaking phase during which a pipe is established between the two processes. Because UDP doesn't have a pipe, when a process wants to send a batch of bytes to another process, the sending process must attach the destination process's address to the batch of bytes. And this must be done for each batch of bytes the sending process sends. As an analogy, look at a group of 20 persons who take five taxis to a common destination; as the people enter the taxis, each taxi driver must separately be informed of the destination. In this way, UDP is similar to a taxi service. The destination address is a tuple comprising the IP address of the destination host and the port number of the destination process. We refer to the batch of information bytes along with the IP destination address and port number as the "packet". UDP provides an unreliable message-oriented service model, in that it makes a best effort to deliver the batch of bytes to the destination. It is message-oriented in that batches are bytes that are sent in a single zero operation at the sending side, will be delivered as a batch at the receiving side; this contrasts with TCP's byte-stream semantics. UDP service is best-effort in that UDP makes no guarantee that the batch of bytes will really be delivered. The UDP service in this way contrasts sharply (in several respects) with TCP's reliable byte-stream service model.

After having created a packet, the sending process pushes the packet into the network through a socket. Continuing with our taxi analogy, at the other side of the sending socket, there is a taxi waiting for the packet. The taxi then drives the packet in the direction of the packet's destination address. On the other hand, the taxi does not guarantee that it will finally get the packet to its ultimate destination - the taxi could break down or suffer some other unforeseen problem. In other terms, UDP provides an unreliable transport service to its communication processes - it makes no guarantees that a packet will reach its ultimate destination.

In this section we demonstrate socket programming by developing the same application of the previous section, but this time over UDP. We'll see that the code for UDP is different from the TCP code in many important ways. Especially, there is (1) no initial handshaking between the two processes and therefore no need for a welcoming socket, (2) no streams are attached to the sockets, (3) the sending hosts create packets by attaching the IP destination address and port number to each batch of bytes it sends, and (4) the receiving process must unravel each received packet to get the packet's information bytes. Recall once again our simple application:

1.  A client reads a line from its standard input (keyboard) and sends the line out its socket to the server.
2. The server reads a line from its socket.
3. The server converts the line to uppercase.
4. The server sends the modified line out its socket to the client.
5. The client reads the modified line from its socket and prints the line on its standard output (monitor).

Figure 1 highlights the main socket-related activity of the client and server that communicate over a connectionless (UDP) transport service.

The client-server application using connectionless transport services

UDPClient.java


Here is the code for the client side of the application:



The program UDPClient.java constructs one stream and one socket, as shown in Figure 2. The socket is called clientSocket, and it is of type DatagramSocket. Note that UDP uses a different kind of socket than TCP at the client. Particularly, with UDP our client uses a DatagramSocket, whereas with TCP our client used a Socket. The stream inFromUser is an input stream to the program; it is attached to the standard input, that is, to the keyboard. We had an equivalent stream in our TCP version of the program. When the user types characters on the keyboard, the characters flow into the stream inFromUser. But in contrast with TCP, there are no streams (input or output) attached to the socket. Instead of feeding bytes to the stream attached to a Socket object, UDP will push individual packets through the Datagramsocket object.

 Let's now take a look at the lines in the code that differ considerably from TCPClient.java.

DatagramSocket clientSocket = new DatagramSocket ( ) ;

The line creates the object clientSocket of type DatagramSocket. In contrast with TCPClient.java, this line does not start a TCP connection. Particularly, the client host does not contact the server host upon execution of this line. For this reason, the constructor Datagramsocket ( ) does not take the server host name or port number as arguments. Using our door-pipe analogy, the execution of the above line creates a door for the client process but does not create a pipe between the two processes.

InetAddress IPAddress = InetAddress.getByName ("hostname") ;

UDPClient has one stream      

In order to send bytes to a destination process, we require the address of the process. Part of this address is the IP address of the destination host. The above line invokes a DNS lookup that translates the hostname (in this example, supplied in the code by the developer) to an IP address. DNS was also invoked by the TCP version of the client, although it was done there implicitly rather than explicitly. The method getByName ( ) takes as an argument the hostname of the server and returns the IP address of this same server. It places this address in the object IPAddress of type InetAddress.

byte[ ] sendData = new byte[1024] ;
byte[ ] receiveData = new byte[1024] ;

The byte arrays sendData and receiveData will hold the data the client sends and receives, respectively.

sendData = sentence.getBytes() ;

The above line basically performs a type conversion. It takes the string sentence and renames it as sendData, which is an array of bytes.

DatagramPacket sendPacket = new DatagramPacket (
       sendData,  sendData.length, IPAddress, 9876) ;

This line constructs the packet, sendPacket, which the client will pop into the network through its socket. This packet contains that data that is included in the packet, sendData, the length of this data, the IP address of the server, and the port number of the application (which we have set to 9876). Note that sendPacket is of type DatagramPacket.

clientSocket.send ( sendPacket ) ;

In the above line, the method send ( ) of the object clientSocket takes the packet just constructed and pops it into the network through clientSocket. Once again, note that UDP sends the line of characters in a manner very different from TCP. TCP simply inserted the string of characters into a stream, which had a logical direct connection to the server; UDP creates a packet that contains the address of the server. After sending the packet, the client then waits to receive a packet from the server.

DatagramPacket  receivePacket =
      new DatagramPacket (receiveData, receiveData.length) ;

In the above line. while for the packet from the server, the client creates a place-holder for the packet, receivePacket, an object of type DatagramPacket.
 
clientSocket.receive (receivePacket) ;

The client idles until it receives a packet; when it does receive a packet, it puts the packet in receivePacket.

String modifiedSentence =
    new String(receivePacket.getData ( ) ) ;

The above line extracts the data from receivePacket and performs a type conversion, converting an array of bytes into the string modifiedSentence.

System.out.printIn ( "FROM SERVER:" + modifiedSentence) ;

This line, which is also present in TCPClient, prints out the string modifiedSentence at the client's monitor.

clientSocket.close ( ) ;

This last line closes the socket. Because UDP is connectionless, this line does not cause the client to send a transport-layer message to the server (in contrast with TCPClient).

UDPServer.java


Let's now take a look at the server side of the application;



The program UDPServer.java constructs one socket, as shown in Figure 3. The socket is called serverSocket. it is an object of type DatagramSocket, as was the socket in the client side of the application. Once again, no streams are attached to the socket.

UDPServer has no streams               
 
Let's now take a look at the lines in the code that differ from TCPServer.java.

DatagramSocket serverSocket = new DatagramSocket (9876) ;

The above line constructs the DatagramSocket serverSocket at port 9876. All data sent and received will pass through this socket. Because UDP is connectionless, we do not have to create a new socket and continue to listen for new connection requests, as done in TCPServer.java. If several clients access this application, they will all send their packets into this single door, serverSocket.



The above three lines unravel the packet that arrives from the client. The first of the three lines extracts the data from the packet and places the data in the String sentence; it has an analogous line in UDPClient. The second line extracts the IP address; the third line extracts the client port number, which is chosen by the client and is different from the server port number 9876. (We will discuss client port numbers in some detail in the next section). It is necessary for the  server to obtain the address (IP address and port number) of the client, so that it can send the capitalized sentence back ro the client.

That completes our analysis of the UDP program pair. To test the application, you install and compile UDPClient.java in one host and UDPServer.java in another host. (Be sure to include the proper hostname of the server in UDPClient.java). Then carry out the two programs on their respective hosts. Unlike with TCP, you can first execute the client side and then the server side. This is because the client process does not attempt to start a connection with the server when you execute the client program. Once you have executed the client and server programs, you may use the application by typing a line at the client.


Tags

processes, hostname, tuple

Copy Right

The contents available on this website are copyrighted by TechPlus unless otherwise indicated. All rights are reserved by TechPlus, and content may not be reproduced, published, or transferred in any form or by any means, except with the prior written permission of TechPlus.