How to implement TCP server in Java (1)

In these days I feel comfortable Spring, but it has been suddenly very cold from last week. That’s why I have a sore throat.

By the way, I don’t know why, but I have to implement a server from scratch using sockets recently. So I write about how to implement TCP server in Java, in addition to organizing my ideas.

Handling server sockets in Java

There are three ways to handle server sockets in Java SE 7.

    • First, it’s what is called “an ordinary socket API”. We have had it since JDK 1.0, (or this the good old API have existed since 1996) and it’s to use java.net.ServerSocket.
    • Second, there is another which handle socket in called “Non-blocking” mode. It’s mainly to use ServerSocketChannel and Selector in java.nio.channels package. It’s added in JDK 1.4.
    • And last, there is the last one which handle socket asynchronously. It’s mainly to use AsynchronousServerSocketChannel in java.nio.channels package, too. It’s added in JDK 1.7

To use java.net.ServerSocket

At first we should start from basic point. Let’s try writing echo-server using ordinary socket API that was already active when I was high school student. Although it’s called “ordinary socket API”, the others also handle “ordinary socket” but in defferent way.

This API is very simple. See following code.

try (ServerSocket listener = new ServerSocket();) {
    listener.setReuseAddress(true);
    listener.bind(new InetSocketAddress(8080));
    System.out.println("Server listening on port 8080...");
    while (true) {
        try (Socket socket = listener.accept();) {
            InputStream from = socket.getInputStream();
            OutputStream to = socket.getOutputStream();
            Bytes.copy(from, to);
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

The proccess is,

  1. To instantiate a ServerSocket and bind to a port.
  2. Waiting for an incomming connection from the client, (or the thread is blocked at the method ServerSocket#accept() calling) and obtain a Socket by ACCEPTing the connection.
  3. To do something over the Socket’s streams.
  4. Closing the Socket.
  5. Continuing from waiting for new connection.

Then, run this.

$ java SocketServer
Server listening on port 8080...

Good, our server is running. Let’s try connecting from another terminal.

$ telnet localhost 8080
Trying ::1...
Connected to localhost.
Escape character is '^]'.

It’s OK. Now we have a connection to our server. Input something to the terminal, and get output as is. Congratulations! …But this server has a big problem.

Multithreading

The problem is that the server can handle only one connection at the same time. To get it, connect from some terminals. The others’ connections are not handled unless one’s is closed.

That’s because we handle a Socket one by one in the previous code. Therefore, we make it multithreaded.

ExecutorService worker = Executors.newCachedThreadPool();
try (ServerSocket listener = new ServerSocket();) {
    listener.setReuseAddress(true);
    listener.bind(new InetSocketAddress(8081));
    System.out.println("Server listening on port 8081...");
    while (true) {
        final Socket socket = listener.accept();
        worker.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    InputStream from = socket.getInputStream();
                    OutputStream to = socket.getOutputStream();
                    Bytes.copy(from, to);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        socket.close();
                    } catch (IOException e) {
                    }
                }
            }
        });
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    worker.shutdown();
}

It’s done. Now we have a very practical echo-server which is able to handle connections at the same time.

Do you have peace of mind? It’s too early. Remember that there are the two other ways to handle server sockets. They have some good points which this “ordinary socket API” don’t have. (But also have some bad points) Next time, let’s check how to use the second, “Non-blocking” API.

One thought on “How to implement TCP server in Java (1)”

Leave a Reply