Site hosted by Angelfire.com: Build your free website today!

Java networking

In any computer network two programs can communicate in the following way. Each computer has a large number of ports. These are like conection points. The two programs that intend to communicate do so at one such port. Each port has its own number. The two communicating programs are called server and client. The server initially connects to a port in its own computer, and waits. Then the client (which is possibly running on a different machine) connects to the same port on the server's machine. Once both the server and client have connected to the port communication begins.

Here are the steps in this process: The server is just like any ordinary program running in a computer. Each computer is equipped with some ports.

Next, the server connects to one of the ports. This process is called binding to a port. The connection is called a server socket. The Java server code that does this is:
ServerSocket ss = new ServerSocket(1234); /* 1234 is some arbitrary 
                                             port number*/
After binding the server waits indefinitely. This is like letting out a hook through the port hole and waiting for someone to pull at the hook. The Java server code is
Socket s = ss.accept();
Compare this with a typical C code:
char c;
c = getchar();
The function waits indefinitely for the user to input a character from the keyboard. The moment the user inputs a character the getchar function returns and stored the input character into c.
The client is another program that runs on a possibly different machine.
It knows the name of the machine where the server is running. (The name is usually like "www.isical.ac.in" or an IP address "202.54.54.145".) Also it knows the port number where the server is bound. In the next step the client connects to this port of the server's computer. The connection is called a (client) socket. You may think of a server socket as a hook projecting out through the port hole, and a (client) socket as rope that the client has thrown over this hook. The Java client code is
Socket sock = new Socket("www.isical.ac.in",1234); 
                         /* The client knows the number 1234 */
The momment the rope touches the hook, the hook pulls the rope in, and connection is established. This means that the line
Socket s = ss.accept();
now finishes execution. The client socket is now stored in s.
The hook is let out again waiting for the next client. Again the server executes
Socket s = ss.accept();
Typically, this line is inside a loop. Everytime a client is found, its Socket is extracted, and the loop again waits for the next client.
The next client may run on yet another machine. This client executes the following Java code just like the last client.
Socket sock = new Socket("www.isical.ac.in",1234); 
The same rope throwing process is repeated.

A simple Java server

In this example we shall ignore the possibility of connecting to more than one client. Our server shall bind the port 3452 (arbitrary number), wait indefinitely for a client, write "I can hear you!" to the client once a client conects to the server, and then exits.
import java.net.*;
import java.io.*;

public class AServer {

    public static void main(String args[]) throws Exception {
	ServerSocket ss = new ServerSocket(3452);
	System.out.println("Listening...");
	Socket s = ss.accept();
	System.out.println("Client detected "+s);

	InputStream in = s.getInputStream();
	OutputStream out = s.getOutputStream();

	byte[] buffer = new byte[1000];
	in.read(buffer);
	System.out.println("Client says:\n"+new String(buffer));
	
	out.write("I can hear you!".getBytes());
	out.flush();

    }
}
We have already explained the first part of this program. We shall now see what the bold part does. A Socket is like a rope-way that can carry messages in either direction. For this we need to extract two Streams from a Socket: an InputStream for reading what comes from the remote end of the rope, and an OutputStream to send messages to the remote end. We are looking at the Server program, so the remote end means the client end. The following code
byte[] buffer = new byte[1000];
in.read(buffer);
System.out.println("Client says:\n"+new String(buffer));
reads the first 1000 bytes (or whatever is available) from the remote end, and prints it on the screen. All reading and writing takes place in terns of bytes. Notice how we change an array of bytes to a String in order to print it on screen.

Similarly, the following code sends the String "I can hear you!" to the client.

out.write("I can hear you!".getBytes());
out.flush();
Notice the use of the getBytes() function of the String class. It converts a String into an array of bytes suitable to be sent to an OutputStream. The out.flush() gurantees that the entrie String arrives at the other end. Sometimes, to optimise performance the computer waits for more message to accumulate in a temporary buffer before sending them to the client. The flush() command forces the computer to send all the buffered contents to the client.

A simple client

The following client program should not be difficult to understand. It accepts the name and port of the server from the command line. While experimenting with client and server you may run both the programs on the same computer. Then you do not need to know the name of the computer. Just writing "localhost" will work.
import java.net.*;
import java.io.*;

public class AClient {

    public static void main(String args[]) throws Exception {
	System.out.println("Connecting...");
	String name = args[0];
	int port = Integer.parseInt(args[1]);
	Socket s = new Socket(name,port);

	InputStream in = s.getInputStream();
	OutputStream out = s.getOutputStream();

	out.write("Hello!\n".getBytes());
	out.flush();
        byte[] buffer = new byte[1000];
	in.read(buffer);
	System.out.println("The remote machine says:\n"+new String(buffer));
    }
}