Java Socket Programming

Java Socket Programming

This page contains some help on Java Socket programming techniques and a link to a my sample Java socket Applet that communicates using both TCP and UDP protocols to server programs.

Contents

Socket communication
Programming with Java sockets
Obtaining host details
Connection oriented communication
Connectionless communication

Java socket communication Applet


Socket Communication Overview

There are two forms of socket communication, connection oriented and connectionless. The TCP/IP protocol suite supports these using two different protocols, TCP (Transmission Control Protocol) UDP (User Datagram Protocol).

TCP (Transmission Control Protocol): TCP is a connection oriented, transport layer protocol that works on top of IP. TCP packets are encapsulated inside IP packets when data is transferred across the network. TCP provides a connection oriented virtual circuit, which is permanent throughout the session between the local and remote hosts. The circuit has to be established before data transfer can begin. A connection is based on the host IP address and the "port" or channel that the server is listening on. The client will send out a send a number of initialisation packets to the server so that the circuit path through the network can be established, when communication is over additional packets are used to release the circuit. These additional packets are the overhead associated with TCP. However, the overhead is quickly regained because of the built-in features of TCP.

Once established all packets are sent along the same path, as a stream of data, each packet does not need to carry destination details with it. A host will usually establish two streams, one for incoming and one for out going data. TCP provides other mechanisms to ensure that data integrity is maintained. Packets are numbered to avoid lost packets and incorrect ordering. Flow control is used, allowing variable data transmission rates to avoid buffer overflow and full-duplex transmission is also provided. These features reflect the fact that TCP is considered a reliable transmission protocol, unlike UDP, which is considered unreliable.

UDP (User Datagram Protocol): UDP is a connectionless transport layer protocol that also sits on top of IP. Unlike TCP, UDP provides no data integrity mechanisms except for a single checksum, and unlike TCP does not establish a connection to the destination before sending any data. UDP, simply packages it’s data into, what is known as a Datagram, along with the destination address and port number and sends it out onto the network. If the destination host is alive and listening it will receive the Datagram if not it will be discarded. Because there is no guaranteed delivery, as there is with TCP, there is a possibility that datagrams will be lost corrupted or delivered in the wrong order. If such facilities are required they must be added to the application manually by the programmer. The minimal implementation of UDP quality of service has led it to be referred to as Unreliable Datagram Protocol.

However, UDP does have it’s advantages, because the protocol has few built-in facilities it has a very low management overhead. The lack of "permanent" connection also means that UDP can adapt better to network failures, as packets can be routed elsewhere to get to their destination. There are some well-known examples of UDP, such as DNS lookups, PING and SNMP. The common factor with these examples is small message length, to keep packets small, and "query based" applications that are not dependent on data reliability.

Network Byte Order and data formatting

Before introducing the details of Java Socket communication I will first discuss the issue of Network byte ordering. This is important because the network and application often interpret data in different ways. Network byte order is the standard way in which bytes are ordered for network communication. It represents the order in which bytes should be written when sent across the network. Network byte order says that the high-byte (the byte on the right) should be written first and low-byte (the byte on the left) last. For example, the following byte representation of an integer, 10 12 45 32 should be written 32 45 12 10 when sending it across the network.

It is also important to consider data types if a Java client communicates with an application written in another language. Because of it’s platform neutrality, Java stores some of it’s data types in "unfamiliar" formats. The most obvious is the 16bit char, which is actually a Unicode format character and not an ASCII format character. Unicode Text Format (UTF) is a character-encoding format that is large enough to represent many different language characters and not just English. Therefore it is important that data being sent to non-Unicode software is not in UTF and if necessary id "de-coded" before it is sent. This can be achieved using Java’s filter streams.

Back to top of page


Java Sockets an Overview

Class InetAddress
Class InetAddress Sample Code

Socket communication: The Java Classes

Java uses many stream-based mechanisms throughout the language to achieve I/O. For example all file I/O and memory I/O in Java is achieved through streams. Most messaging is also carried out using streams although basic datagram implementations are also supported. Classes are provided for client and server Internet working, but it must be noted that when using Applets the Java Security Manager imposes certain restrictions. The most significant is that an untrusted Applet may only establish connections back to the server from which it was loaded. I will point out other security restrictions specific to classes and methods as they arise during the following outline of Java Internet working classes.

All of the classes listed below are from the
java.net and java.io packages.

Obtaining Internet address information

Class InetAddress

This class provides methods to access host names and IP addresses.

The following methods are provided to create InetAddress objects:

Static InetAddress getLocalHost() throws UnknownHostException This method returns an InetAddress object for the local machine.

Static InetAddress getByName(String host) throws UnknownHostException This method returns an InetAddress object for the specified host name. The host name can be either a pneumonic identifier such as "www.Java.com" or an IP address such as 121.1.28.54. This is the only method that can be used by a client to get remote hosts details.

The following methods are provided to extract information from and InetAddress object.

byte[] getAddress() This method returns an array of bytes corresponding to the IP address held in the InetAddress object. The array is in network byte order i.e. high byte first (back to front) and must be converted to a string before being displayed to the screen.

String getHostName() Returns the host name held in the InetAddress object. If the host name is not already known an attempt is made to look it up, if this fails the IP address is returned as a string.

Exception Errors

UnknownHostException This is a subclass of IOException and indicates that the host name could not successfully be identified.

SecurityException This error is thrown if the Java security manager has restricted the desired action from taking place. Currently an Applet may only create an InetAddress object for host that it originated from, i.e. the host web server. Any attempt to create an InetAddress object for another host will throw this exception.

Class InetAddress sample code

The method below, getLocalnetdetails(), simply creates an InetAddress object and retrieves the local host name and IP address. It uses another method called toText to convert the byte array IP address to a string so that it can be sent to the TextArea object called "output".

public void getLocalnetdetails (){

try {
InetAddress myself = InetAddress.getLocalHost ();
output.appendText ("Local hostname : " + myself.getHostName () + "\n");
output.appendText ("Local IP Address : " + toText (myself.getAddress ()) + "\n");
}
catch (UnknownHostException ex){
output.appendText ("Failed to find myself:");
ex.printStackTrace ();
}

}// END getnetdetails

The following method, printRemoteAddress(String name), performs the same actions as the method above but this time for the remote host. It accepts the name of the host and prints the result. This method catches the Security Host Exception as a precaution.

public void printRemoteAddress (String name){

try {
output.appendText("Looking up " + name + "..." + "\n");
InetAddress machine = InetAddress.getByName (name);
output.appendText("Host name : " + machine.getHostName ()+ "\n");
output.appendText("Host IP : " + toText (machine.getAddress ())+ "\n");
}
catch (UnknownHostException e){
output.appendText ("Failed to lookup " + name + "\n");
e.printStackTrace ();
}
catch (SecurityException e){
output.appendText ("Failed to find host other than host web server:");
e.printStackTrace ();
}

} // End printRemoteAddress

Back to top of page


Connection oriented communication

Class Socket
Class Socket Sample Code
Class ServerSocket
Class ServerSocket Sample Code

Class Socket (TCP Client Connections)

A Socket is a Java representation of a TCP network connection. In order to communicate with a remote host the Java client must first create a Socket, which will establish the TCP connection. In doing so a host name and port number must be specified. There must be a server actively listening on the specified port or the connection will fail with IOException.

These constructors allow the Socket connection to be established.

Socket(String host, int port) throws IOException This creates a Socket and connects to the specified host and port. Host can be a host name or IP address and port must be in a range of 1-65535.

Socket(InetAddress address, int port) throws IOException This creates a Socket and connects to the specified port of the host address. The port must be in a range of 1-65535.

These methods allow the remote host address and local or remote port numbers to be identified. These methods also allow for the creation of input and output streams.

InetAddress getInetAddress() This method returns the IP address of a remote host.

int getPort() This method returns the port number of the remote host to which the Socket is connected.

int getLocalPort() The local port number is returned by this method, the port number used to create the Socket.

InputStream getInputStream()throws IOException This method returns an InputStream that allows the Socket to receive data across the TCP connection. An InputStream can be buffered or standard.

OutputStream getOutputStream()throws IOException This method returns an OutputStream that allows the Socket to send data across the TCP connection. An OutputStream should be buffered to avoid lost bytes, especially when the Socket is closed.

void close() throws IOException This method closes the Socket, releasing any network or system resources being used.

Exception Errors

IOException This is a generic Input Output error that can be thrown by many of the method mentioned here.

SecurityException This error is thrown if the Java security manager has restricted the desired action from taking place. Applets may not open sockets to any host other than the originating host, i.e. the web server. Any attempt to open a socket to a destination other than the host address will cause this exception to be thrown.

The following to constructors are part of the DataOutputStream and DataInputStream classes and not Socket class but as they are used in the example code below I will list them here.

DataOutoutStream(OutoutStream out) This constructs a DataOutoutStream attached to a specified OutputStream. A data is broken down into byte format and transmitted to the attached stream.

DataInputStream(InputStream in) This constructs a DataInputStream attached to the specified InputStream. Byte high order format data is read from the InputStream and converted to low order data when passed to the attached DataInputStream.



Class Socket (TCP Client Connections) Sample Code

The following method, connect(int port),Accepts the port number and creates a socket to the host server. Once the Socket is created we must get the raw input and output streams associated with the Socket. These are called rawIn and rawOut. rawOut is then setup as a buffered. In order to understand these streams we must convert them to Data streams. The reason this is required is because the raw I/O streams can only understand byte format data, where as we wish to send strings and integers. Creating a DataInputStream from a raw ImputStream allows the conversions to take place automatically.

// Input and output streams for TCP socket
protected DataInputStream in;
protected DataOutputStream out;


protected Socket connect (int port) throws IOException
{

// Connect method
output.appendText ("\nConnecting to " + server + " Port " + port + "\n");
Socket socket =
new Socket (server, port);
OutputStream rawOut = socket.getOutputStream ();
InputStream rawIn = socket.getInputStream ();
BufferedOutputStream buffOut = new BufferedOutputStream (rawOut);
out =
new DataOutputStream (buffOut);
in =
new DataInputStream (rawIn);
return socket;

} // END connect


Class ServerSocket (TCP Server Connections)

A ServerSocket is a mechanism by which a server can accept connections from clients across a network. The server will open the ServerSocket and wait or listen for connections from clients. The ServerSocket class creates a Socket for each client connection. The server then handles the connections in the normal manner with Input and Output streams.

ServerSocket(int port, int count) throws IOException This constructs a ServerSocket that listens on the specified port, argument 1, of the local machine. Argument 1 is mandatory and must be supplied, but argument 2, the outstanding connection requests parameter, may be omitted. If so the default of 50 is used. If the count option is used it specifies the number of outstanding requests that should be queued by the operating system before discarding. This option is useful if the server is slow at accepting requests or if you do not wish the server to get flooded by to many clients.

These methods allow connections to accepted when listening and information about the server socket to be obtained.

Socket accept() throws IOException This method blocks until a client makes a connection to the port on which the ServerSocket is listening. A Socket is returned corresponding to the TCP connection from the client.

void close() throws IOException This method closes the ServerSocket. What is significant is that it does not close any of the currently accepted connections, they are unaffected, it only stops additional connections being made by clients.

int getLocalPort() Returns the integer value of the port on which ServerSocket is listening. This is useful if the server specifies port number 0, which means that the operating system assigns the next unused port.

Exception Errors

IOException This is a generic Input Output error that can be thrown by many of the method mentioned here. When creating a socket many different failures could occur, i.e. attempting to create a socket on a port that is already in use.

SecurityException Applets may not act as servers, so the Security Manager will throw the exception if the Applet attempts to create a ServerSocket, i.e. Java servers using ServerSocket must be applications.


Class ServerSocket (TCP Server Connections) Code Example

The method below will accepts a connection on a given port. Firstly a ServerSocket is used to accept the connection and when the connection is accepts a new socket called client is used for communication to the client. Communication throught the client socket is achieved in the same way as client communication.

static Socket accept (int port) throws IOException {

System.out.println ("Starting on port " + port);
// Setup ServerSocket
ServerSocket server =
new ServerSocket (port);
System.out.println ("Waiting");
Socket ClientSocket = server.accept ();
// Extract the address of the connected user
System.out.println ("Accepted from " + ClientSocket.getInetAddress ());
server.close ();
// return the client sock so that communication can begin
return ClientSocket;
}

}

Back to top of page


Datagram Communication

When using Datagram communication there are several differences to stream based TCP. Firstly a datagram packet is required, as we do not have a "permanent" stream we cannot simply read and write data to and from a communication channel. Instead we must construct packets, datagrams, that contains the destination address, the port number, the data and the length of the data. Therefore we must deal with creating and dissecting packets before we can send or receive data.

Class DatagramPacket
Class DatagramPacket Sample code
Class DatagramSocket
Class DatagramSocket Sample Code

Class DatagramPacket

This class is used to create the datagram packets for transmission and receipt with data and address information.

DatagramPacket(byte inbuf[], int buflength) This statement constructs a datagram packet for receiving datagrams. Inbuff is a byte array that holds the data received and buflength is the maximum number of bytes to read. We are effectively ignoring the address and port information held within the packet.

DatagramPacket(byte inbuf[], int buflength, InetAddress iaddr, int port) This statement constructs a datagram packet for transmission. As above inbuff holds the data to be sent, buflength is the amount of data to be sent, iaddr is the address of the destination and port is the port number on the remote host.

These methods allow the contents of a Datagrampacket to be queried.

InetAddress getAddress() This method returns the IP address of the packet source or destination.

int getPort() Returns the port number of the packet. This will be either the local port number for datagram packets being sent or remote port number for packets being received.

byte() getData() This method returns a byte array corresponding to the data held in the DatagramPacket object.

int getLength() This method returns the length of the UDP packet, the majority of time this will be less than the buffer size, if not a larger buffer should be allocated.

Class DatagramPacket Sample Code

The following method buildPacket() accepts a string message and host details and returns a new DatagramPacket object. Because the data of the packet must be in byte format and not a String it must be converted before it can be stored. To do this I use a ByteArrayOutputStream, and pass the message String through it.

protected DatagramPacket buildPacket (String message, String host, int port) throws IOException {

// Create a byte array from a string
ByteArrayOutputStream byteOut =
new ByteArrayOutputStream ();
DataOutputStream dataOut =
new DataOutputStream (byteOut);
dataOut.writeBytes(message);
byte[] data = byteOut.toByteArray ();
//Return the new object with the byte array payload
return new DatagramPacket (data, data.length, InetAddress.getByName(host), port);

}


Class DatagramSocket

The DatagramSocket class is used to create sockets through which we send and receive DatagramPackets. As with TCP, a UDP DatagramSocket must listen on a port number.

DatagramSocket() throws SocketException Here we create a DatagramSocket using the next available free port number.

DatagramSocket(int port) throws SocketException Here we create a DatagramSocket using the specified port number.

These methods allow us to send and receive through the DatagramSocket and to determine the port number and close the socket.

void send(DatagramPacket p) throws IOException This method sends the packet out onto the network.

syncronized void receive(DatagramPacket p) throws IOException This method receives a packet into the specified DatagramPacket. This method blocks until a packet has been received successfully.

int getLocalPort() Returns the integer value of the port on which DatagramSocket is listening.

syncronized void close() This method closes the DatagramSocket.

IOException When creating a DatagramSocket many different failures could occur, i.e. attempting to create a socket on a port that is already in use. All errors throw IOException.

SecurityException Applets are restricted from sending or receiving datagrams from a destination other than it’s originating server. It is possible that an Applet could receive a stray datagram by mistake, this should be accounted for.


Class DatagramSocket Sample Code

The method below receives a DatagramPacket and displays the data contents. Before the contents can be displayed, the byte array held in the packet must be converted into a string. This is similar to creating the byte array above, a ByteArrayOutputStream, is used in conjunction with a DataInputStream, which converts the bytes to a usable data format. The string is simply read from the DataInputStream until no more data exists.


protected void receivePacket () throws IOException {

byte buffer[] = new byte[65535];
DatagramPacket packet =
new DatagramPacket (buffer, buffer.length);
socket.receive (packet);
// Convert the byte array read from network into a string
ByteArrayInputStream byteIn = new ByteArrayInputStream (packet.getData (), 0, packet.getLength ());
DataInputStream dataIn = new DataInputStream (byteIn);
// Read in data from a standard format
String input = "";
while((input = dataIn.readLine ()) != null)
output.appendText("SERVER REPLIED : " + input + "\n");

}

Back to top of page


1997 Michael J. Golding. All rights reserved.