Vladislav Rastrusny
Vladislav Rastrusny

Reputation: 29985

Java: nice way to stop threaded TCP server?

I have the following structure for TCP client-server communication:

The question is how to gracefully stop the whole system? I can stop acceptor thread by just closing ServerSocket. It will cause accept() blocking call to throw SocketException. But how to stop workers? They read from stream and this call is blocking. According to this streams does not throw InterruptedException and thus worker cannot be interrupt()'ed.

It looks like I need to close worker socket from another thread, right? For this, socket should be made a public field or a method should be provided in worker to close it. Will this be nice? Or may be my whole design is flawed?

Upvotes: 5

Views: 5493

Answers (3)

Edwin Dalorzo
Edwin Dalorzo

Reputation: 78589

You must not simply stop the server. The shutdown process might take a while while cleanup occurs because you need to ensure consistency.

Imagine a database server, if you simply shut it down while it is carrying out transactions you may leave its data inconsistent. That's why it typically takes a while to shutdown the server.

  • You must first stop accepting new connections in the server.
  • Then you can either wait for the current worker threads to finish their work and then close the server and shutdown officially.
  • Or you force the worker threads to close their connections with the
    client (probably using some sort
    of flag as suggested). This might imply some cleanup to leave data consistent, for instance revert trasnsactions or any kind of changes you have done in files or in memory.

Closing the connections with the clients in the server side should cause the clients to get a EOF on their sides as far as I understand.

[EDIT-1]

I have delved a bit on the issue, just because I had not used sockets in a while and because I found the question interesting. I think as it has been well pointed out by others, the only option is to close the socket, which according got Javadocs will automatically close the input and output streams/

If there are chances that the thread is not IO-blocked, but in wait state or sleeping, I think it is still recommended to issue a Thread.interrupt() for the corresponding worker thread of a given socket; because there cannot be certainty of the blocking of state of every thread.

public static class IOServerWorker implements Runnable{

        private Socket socket;

        public IOServerWorker(Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            String line = null;
            try{
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while( (line = reader.readLine())!=null){
                    System.out.println(line);
                }
                reader.close();
            }catch(IOException e){
                //TODO: do cleanup here
                //TODO: log | wrap | rethrow exception
            }
        }
    }

Upvotes: 2

John Vint
John Vint

Reputation: 40256

Your model works appropriately. The best way of interrupting non-interruptable constructs like IO is to close the socket. You can of course handle it before you go into a blocking state, but if the IO functions don't react to interruption you dont really have many good options

Upvotes: 3

Chris Thompson
Chris Thompson

Reputation: 35598

I would suggest using a boolean flag that the workers check periodically. Call the flag shouldStop and if it's set to true, the worker cleans up and then dies. Following this method would allow you to implement some clean-up code so you don't leave resources hanging, etc.

Upvotes: 2

Related Questions