Friday 24 March 2017

TCP/IP Server Sockets & Datagrams - Java Tutorials

TCP/IP Server Sockets

As we mentioned earlier, Java has a different socket class that must be used for creating server applications. The ServerSocket class is used to create servers that listen for either local or remote client programs to connect to them on published ports. Since the Web is driving most of the activity on the Internet, this section develops an operational web (http) server.

ServerSockets are quite different from normal Sockets. When you create a ServerSocket, it will register itself with the system as having an interest in client connections. The constructors for ServerSocket reflect the port number that you wish to accept connections on and, optionally, how long you want the queue for said port to be. The queue length tells the system how many client connections it can leave pending before it should simply refuse connections. The default is 50. The constructors might throw an IOException under adverse conditions. Here are the constructors:

ServerSocket(int port):  Creates server socket on the specified port with a queue length of 50.

ServerSocket(int port, int maxQueue):  Creates a server socket on the specified port with a maximum queue length of maxQueue.

ServerSocket(int port, int maxQueue, InetAddress localAddress):  Creates a server socket on the specified port with a maximum queue length of maxQueue. On a multihomed host, localAddress specifies the IP address to which this socket binds.

ServerSocket has a method called accept( ), which is a blocking call that will wait for a client to initiate communications, and then return with a normal Socket that is then used for communication with the client.

Java 2, version 1.4 added the getChannel( ) method to ServerSocket. This method returns a channel connected to the ServerSocket object. Channels are used by the new I/O classes contained in java.nio.




Datagrams

For most of your internetworking needs, you will be happy with TCP/IP-style networking. It provides a serialized, predictable, reliable stream of packet data. This is not without its cost, however. TCP includes many complicated algorithms for dealing with congestion control on crowded networks, as well as pessimistic expectations about packet loss. This leads to a somewhat inefficient way to transport data. Datagrams provide an alternative.

Datagrams are bundles of information passed between machines. They are somewhat like a hard throw from a well-trained but blindfolded catcher to the third baseman. Once the datagram has been released to its intended target, there is no assurance that it will arrive or even that someone will be there to catch it. Likewise, when the datagram is received, there is no assurance that it hasn’t been damaged in transit or that whoever sent it is still there to receive a response.

Java implements datagrams on top of the UDP protocol by using two classes: The DatagramPacket object is the data container, while the DatagramSocket is the mechanism used to send or receive the DatagramPackets.


DatagramPacket

DatagramPacket defines several constructors. Four are described here. The first constructor specifies a buffer that will receive data, and the size of a packet. It is used for receiving data over a DatagramSocket. The second form allows you to specify an offset into the buffer at which data will be stored. The third form specifies a target address and port, which are used by a DatagramSocket to determine where the data in the packet will be sent. The fourth form transmits packets beginning at the specified offset into the data. Think of the first two forms as building an “in box,” and the second two forms as stuffing and addressing an envelope. Here are the four constructors:

      DatagramPacket(byte data[ ], int size)
      DatagramPacket(byte data[ ], int offset, int size)
      DatagramPacket(byte data[ ], int size, InetAddress ipAddress, int port)
      DatagramPacket(byte data[ ], int offset, int size, InetAddress ipAddress, int port)

There are several methods for accessing the internal state of a DatagramPacket. They give complete access to the destination address and port number of a packet, as well as the raw data and its length. Here are some of the most commonly used:

InetAddress getAddress( ):  Returns the destination InetAddress, typically used for sending.

int getPort( ):  Returns the port number.

byte[ ] getData( ):  Returns the byte array of data contained in the datagram. Mostly used to retrieve data from the datagram after it has been received.

int getLength( ):  Returns the length of the valid data contained in the byte array that would be returned from the getData( ) method. This typically does not equal the length of the whole byte array.


Datagram Server and Client

The following example implements a very simple networked communications client and server. Messages are typed into the window at the server and written across the network to the client side, where they are displayed.

  // Demonstrate Datagrams.
  import java.net.*;

  class WriteServer {
    public static int serverPort = 998;
    public static int clientPort = 999;
    public static int buffer_size = 1024;
    public static DatagramSocket ds;
    public static byte buffer[] = new byte[buffer_size];

    public static void TheServer() throws Exception {
      int pos=0;
      while (true) {
        int c = System.in.read();
        switch (c) {
          case -1:
            System.out.println("Server Quits.");
            return;
          case '\r':
            break;
          case '\n':
            ds.send(new DatagramPacket(buffer,pos,
               InetAddress.getLocalHost(),clientPort));
            pos=0;
            break;
          default:
            buffer[pos++] = (byte) c;
        }
      }
    }

    public static void TheClient() throws Exception {
      while(true) {
        DatagramPacket p = new DatagramPacket(buffer,buffer.length);
        ds.receive(p);
        System.out.println(new String(p.getData(),0,p.getLength()));
      }
    }

    public static void main(String args[]) throws Exception {
      if(args.length == 1) {
        ds = new DatagramSocket(serverPort);
        TheServer();
      } else {
        ds = new DatagramSocket(clientPort);
        TheClient();
      }
    }
  }

This sample program is restricted by the DatagramSocket constructor to running between two ports on the local machine. To use the program, run

  java WriteServer

in one window; this will be the client. Then run

  java WriteServer 1

This will be the server. Anything that is typed in the server window will be sent to the client window after a newline is received.

This example requires that your computer be connected to the Internet.


Inet4Address and Inet6Address

As mentioned at the start of this chapter, Java 2, version 1.4 added support for IPv6 addresses. Because of this, two new subclasses of InetAddress were created: Inet4Address and Inet6Address. Inet4Address represents a traditional style, IPv4 address. Inet6Address encapsulates a new-style IPv6 address. Because they are subclasses of InetAddress, an InetAddress reference can refer to either. This is one way that Java was able to add IPv6 functionality without breaking existing code or adding many more classes. For the most part, you can simply use InetAddress when working with IP addresses because it can accommodate both styles.


The URI Class

Java 2, version 1.4 added the URI class, which encapsulates a Uniform Resource Identifier. URIs are similar to URLs. In fact, URLs constitute a subset of URIs. A URI represents a standard way to identify a resource. A URL also describes how to access the resource.

No comments:

Post a Comment