I have a server thread with this code:
public void run() {
try {
ServerSocket server;
EneaLog.printLog("Server is running.");
server = new ServerSocket(this.portnumber);
while (true) {
new EneaServerConnection(server.accept(), this.project,stopped).start();
if (stopped) {
EneaLog.printLog("Server safe-shutdown completed.");
EneaLog.printLog("Hi!");
server.close();
return;
}
}
} catch (IOException ex) {
Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex);
project.getExceptionHandler().handler(ex);
}
}
and a shutdown method like this:
public void shutdown() {
EneaLog.printLog("Server shutdown NOW!");
stopped = true;
}
I want that shutdown can unblock thread that are waiting on server.accept() otherwise I must wait for connection before server shutdown.
I can't do server.close() in shutdown() because I must signal to registered client that server is coming down.
Any ideas?
I try to design my code so that it can be "shutdown" with an interrupt. Mainly, this is because the
Executor
framework in Java's concurrency package usesinterrupt
to cancel running tasks. Also, the "shutdown" task doesn't have to know any internals of the task being killed.However, a call to
accept
will not respond to an interrupt unless it is created from aServerSocketChannel
. A server created with aServerSocket
constructor will ignore interrupts, and I haven't found a way to reconfigure this.If you can't change the code that creates the server, arrange for another thread to call
close
on the server socket. This will also raise an exception in thread blocked onaccept
, regardless of the method used to create the server socket.This turns out to be a really big pain when using SSL. A JSSE socket is not created from an
InterruptibleChannel
, and won't respond to a simple interrupt on the thread.I just noticed that the question says that the server can't be closed without notifying the client. Successfully interrupting a socket results in its closure.
On a call to
accept
this shouldn't be a problem, since the client is not connected if the server socket is blocked in accept. That should only be an issue forSocket
instances, that represent current connections.If that doesn't satisfy the notification requirements, a rework to use NIO's
ServerSocketChannel
in non-blocking mode may be necessary.You should be able to close the socket from another thread.
I've been faced to the same problem. My working solutions consists into closing the ServerSocket object (serverSocket.close()) ; doing this will cause the accept() method to throw a SocketException, which is what you want to do.
Vincent
Have you tried Thread.interrupt() ?
Neither interrupt (that's dependent on interrupt points in the same way cancellation is dependent on cancellation points) nor close will do it (accept does not responsed to closing its file descriptor). You'll have to communicate with the accept (try sendto, with a shutdown notification) to notify it to not continue accepting. At least this is the case on linux; don't know what it's like on other platforms.