Sockets programming in Java


This tutorial presents an introduction to sockets programming over TCP/IP networks and shows how to write client/server applications in Java.

Note: All the classes related to sockets are in the java.net package, so make sure to import that package when you program sockets.

How do I open a socket?

If you are programming a client, then you would open a socket like this:

        Socket MyClient;
        MyClient = new Socket("Machine name", PortNumber);
Where Machine name is the machine you are trying to open a connection to, and PortNumber is the port (a number) on which the server you are trying to connect to is running. When selecting a port number, you should note that port numbers between 0 and 1,023 are reserved for privileged users (that is, super user or root). These port numbers are reserved for standard services, such as email, FTP, and HTTP. When selecting a port number for your server, select one that is greater than 1,023!

In the example above, we didn't make use of exception handling, however, it is a good idea to handle exceptions. (From now on, all our code will handle exceptions!) The above can be written as:

        Socket MyClient;
        try {
           MyClient = new Socket("Machine name", PortNumber);
        }
        catch (IOException e) {
            System.out.println(e);
        }
If you are programming a server, then this is how you open a socket:
        ServerSocket MyService;
        try {
           MyServerice = new ServerSocket(PortNumber);
        }
        catch (IOException e) {
           System.out.println(e);
        }
When implementing a server you also need to create a socket object from the ServerSocket in order to listen for and accept connections from clients.
        Socket clientSocket = null;
        try {
           serviceSocket = MyService.accept();
        }
        catch (IOException e) {
           System.out.println(e);
        }
How do I create an input stream?

On the client side, you can use the DataInputStream class to create an input stream to receive response from the server:

        DataInputStream input;
        try {
           input = new DataInputStream(MyClient.getInputStream());
        }
        catch (IOException e) {
           System.out.println(e);
        }
The class DataInputStream allows you to read lines of text and Java primitive data types in a portable way. It has methods such as read, readChar, readInt, readDouble, and readLine,. Use whichever function you think suits your needs depending on the type of data that you receive from the server.

On the server side, you can use DataInputStream to receive input from the client:

        DataInputStream input;
        try {
           input = new DataInputStream(serviceSocket.getInputStream());
        }
        catch (IOException e) {
           System.out.println(e);
        }
How do I create an output stream?

On the client side, you can create an output stream to send information to the server socket using the class PrintStream or DataOutputStream of java.io:

        PrintStream output;
        try {
           output = new PrintStream(MyClient.getOutputStream());
        }
        catch (IOException e) {
           System.out.println(e);
        }
The class PrintStream has methods for displaying textual representation of Java primitive data types. Its Write and println methods are important here. Also, you may want to use the DataOutputStream:
        DataOutputStream output;
        try {
           output = new DataOutputStream(MyClient.getOutputStream());
        }
        catch (IOException e) {
           System.out.println(e);
        }
The class DataOutputStream allows you to write Java primitive data types; many of its methods write a single Java primitive type to the output stream. The method writeBytes is a useful one.

On the server side, you can use the class PrintStream to send information to the client.

        PrintStream output;
        try {
           output = new PrintStream(serviceSocket.getOutputStream());
        }
        catch (IOException e) {
           System.out.println(e);
        }
Note: You can use the class DataOutputStream as mentioned above.

How do I close sockets?

You should always close the output and input stream before you close the socket.

On the client side:

        try {
           output.close();
           input.close();
           MyClient.close();
        } 
        catch (IOException e) {
           System.out.println(e);
        }
On the server side:
        try {
           output.close();
           input.close();
           serviceSocket.close();
           MyService.close();
        } 
        catch (IOException e) {
           System.out.println(e);
        }

Examples

In this section we will write two applications: a simple SMTP (simple mail transfer protocol) client, and a simple echo server.

 SMTP client

Let's write an SMTP (simple mail transfer protocol) client -- one so simple that we have all the data encapsulated within the program. You may change the code around to suit your needs. An interesting modification would be to change it so that you accept the data from the command-line argument and also get the input (the body of the message) from standard input. Try to modify it so that it behaves the same as the mail program that comes with Unix.
 
import java.io.*;
import java.net.*;

public class smtpClient {
    public static void main(String[] args) {

// declaration section:
// smtpClient: our client socket
// os: output stream
// is: input stream

        Socket smtpSocket = null; 
        DataOutputStream os = null;
        DataInputStream is = null;

// Initialization section:
// Try to open a socket on port 25
// Try to open input and output streams

        try {
            smtpSocket = new Socket("hostname", 25);
            os = new DataOutputStream(smtpSocket.getOutputStream());
            is = new DataInputStream(smtpSocket.getInputStream());
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: hostname");
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to: hostname");
        }

// If everything has been initialized then we want to write some data
// to the socket we have opened a connection to on port 25

        if (smtpSocket != null && os != null && is != null) {
            try {

// The capital string before each colon has a special meaning to SMTP
// you may want to read the SMTP specification, RFC1822/3

                os.writeBytes("MAIL From: k3is@fundy.csd.unbsj.ca\n");
                os.writeBytes("RCPT To: k3is@fundy.csd.unbsj.ca\n");
                os.writeBytes("DATA\n");
                os.writeBytes("From: k3is@fundy.csd.unbsj.ca\n");
                os.writeBytes("Subject: testing\n");
                os.writeBytes("Hi there\n"); // message body
                os.writeBytes("\n.\n");

// keep on reading from/to the socket till we receive the "Ok" from SMTP,
// once we received that then we want to break.

                String responseLine;
                while ((responseLine = is.readLine()) != null) {
                    System.out.println("Server: " + responseLine);
                    if (responseLine.indexOf("Ok") != -1) {
                      break;
                    }
                }

// clean up:
// close the output stream
// close the input stream
// close the socket

                os.close();
                is.close();
                smtpSocket.close(); 
            } catch (UnknownHostException e) {
                System.err.println("Trying to connect to unknown host: " + e);
            } catch (IOException e) {
                System.err.println("IOException:  " + e);
            }
        }
    } 
}

When programming a client, you must follow these four steps:

These steps are pretty much the same for all clients. The only step that
varies is step three, since it depends on the server you are talking to.

 

Echo server

Now let's write a server. This server is very similar to the echo server running on port 7. Basically, the echo server receives text from the client and then sends that exact text back to the client. This is just about the simplest server you can write. Note that this server handles only one client. Try to modify it to handle multiple clients using threads.
 
import java.io.*;
import java.net.*;

public class echo3 {
    public static void main(String args[]) {

// declaration section:
// declare a server socket and a client socket for the server
// declare an input and an output stream

        ServerSocket echoServer = null;
        String line;
        DataInputStream is;
        PrintStream os;
        Socket clientSocket = null;

// Try to open a server socket on port 9999
// Note that we can't choose a port less than 1023 if we are not
// privileged users (root)

        try {
           echoServer = new ServerSocket(9999);
        }
        catch (IOException e) {
           System.out.println(e);
        }

// Create a socket object from the ServerSocket to listen and accept
// connections.
// Open input and output streams

        try {
           clientSocket = echoServer.accept();
           is = new DataInputStream(clientSocket.getInputStream());
           os = new PrintStream(clientSocket.getOutputStream());

// As long as we receive data, echo that data back to the client.

           while (true) {
             line = is.readLine();
             os.println(line);
           }
        }
        catch (IOException e) {
           System.out.println(e);
        }
    }
}