Saturday, August 9, 2008

Stop a thread that's accepting connections

A common approach to implementing a server is to set up its main loop to accept connections from clients, then create separate threads to handle each connection.

But how do you shut down a thread that's blocked in the wait state? It's not enough to simply set the running flag to false, breaking it out of its main loop, as that would leave the server waiting for one last connection before it lets go of its resources and shuts down. The following code shows you how.

public class SimpleServer extends Thread {

private volatile boolean running = false;
ServerSocket serverSock = null;
private int serverPort = 8080;

public SimpleServer (int serverPort) {
this.serverPort = serverPort;
}

/** Begin listening for connections from subscribers. */
public void run() {
System.out.println( "Simple Server started." );

try {
serverSock = new ServerSocket( serverPort );
} catch ( IOException e ) {
System.err.println( e.getMessage() );
}

running = true;
// main loop of the thread
// listens for new subscribers
while( running ) {
Socket sock = null;
try {
// blocks while waiting
sock = serverSock.accept();

// handle the new socket connection
}
catch ( IOException ioe ) {
System.err.println( ioe.getMessage() );
}
finally {
try {
sock.close();
}
catch ( IOException ioe ) {
System.err.println( ioe.getMessage() );
}
}
}
}

/** Check the running flag. */
public boolean isRunning() {
return running;
}

/** Stop the server listen thread. */
public void shutDown() {
running = false;
try {
// open a connection to the server socket,
// because it is blocking on accept
new Socket( serverSock.getInetAddress(),
serverSock.getLocalPort() ).close();
System.out.println("Server shut down normally.");
}
catch(IOException ioe) {
System.err.println( ioe.getMessage() );
}
}
}

The interesting technique here can be found in the shutDown method. After setting the running flag to false we open one more socket connection on the listening port, then immediately close it. This allows the server application to terminate immediately and gracefully.

2 comments:

Anonymous said...

Thanks for this very useful example.

A (possibly) interesting addition I made was to put an "if(running){ }" block around the handling of the connection. This prevents your connection handler being called with the "fake" connection that was made to break out of the while loop.

Anonymous said...

Thank You. You have addressed the exact issue which I had with a great solution.

Thank You,
sumudu.v@gmail.com