I have a thread running in my Swing chat application to listen indefinitely through a socket for datagrams. When I close this application, I have the following code execute:
listenThread.interrupt();
socket.close();
However, interrupt doesn't seem to be stopping the thread, as when the socket closes, the loop continues listening, and throws exceptions since the socket has been closed. How do I get the thread to exit properly so that I can close the socket safely?
interrupt() cannot be used to interrupt an I/O operation such as socket reads or writes. To abort the I/O, closing the socket is the right way. After your thread receives the IOException it should check if it was interrupted in the meantime and then gracefully exit.
Example for the code in your I/O thread:
while( !Thread.currentThread().isInterrupted() ) {
try {
doRead();
} catch ( IOException ioe ) {
// Log exception or whatever
}
}
interrupt() only notifies the thread about someone's intention to stop it. It's up to the thread to properly exit. If thread is waiting on the monitor it will receive InterruptedException, otherwise you can check isInterrupted() on the current thread. However, if it's waiting on IO you may be out of luck and your only choice is to wait for socket time out to expire. Then you will check if thread is interrupted and close the socket.
If it's throwing an exception, catch it and exit the UDP read thread. Throwing an exception when the socket is closed from another thread is expected - make use of it!
Failing that, set the interrupted flag and make the UDP read() return by sending it a datagram on the local TCP stack from a socket in thread requesting the shutdown. UDP is a connectionless message service and is quite happy to receive a datagram from another thread on the same box. The datagram could contain a shutdown instruction, or you could check the isInterrupted flag after every read() return, just in case it's set.
I'm going to assume you've implemented this the easy way and done:
DatagramSocket s = new DatagramSocket( port );
DatagramPacket p = new DatagramPacket( new byte[256], 256);
s.receive( p );
Now, looking at the Javadoc, there's no way to get the DatagramSocket.receive() to throw an InterruptedException. Closing the socket is the only way to get it to stop listening.
A better implementation of this would have been to set a time out on the DatagramSocket using DatagramSocket.setSoTimeout( int ) to something small like 2 seconds, and then check if your server has been interrupted. So you'd end up with something like this for your server code ( doesn't handle exceptions ):
DatagramSocket s = new DatagramSocket( port );
s.setSoTimeout( 2000 ); // 2 second time out
while( running ){ // boolean running flag, check for interrupt here
try{
DatagramPacket p = new DatagramPacket( new byte[256], 256);
s.receive( p );
//do stuff
} catch ( SocketTimeoutException e ){
//timed out
}
}//end while
Related
I am writing a simple client/server chat program. The server handles multiple clients in this way:
public void start(int port)
{
(new Thread(new Runnable()
{
#Override
public void run() {
try{
serverSocket = new ServerSocket(port);
SocketHandler handler;
while(true)
{
handler = new SocketHandler(serverSocket.accept());
handlersList.add(handler);
(new Thread(new SocketHandler(socket))).start();
}
}catch(IOException e)
{
for(SocketHandler handler:handlersList)
handler.close();
}
}
})).start();
}
public void stop() throws IOException
{
serverSocket.close();
}
Basically start() instantiates the ServerSocket and waits for clients to connect indefinitely. Whenever the user wants to close the server, the Server Socket is closed, which causes the accept() to fail and to throw and exception. Then the catch(){} closes the various sockets created. My questions are:
Do I have to close every socket created through serverSocket.accept()?
Is this the right way to stop such a server? That while(true) + use of exceptions for non-exceptional circumstances feels so wrong to me. Is there a better way?
Could I use an ExecutorService and then just call shutdownNow on it? Will the shutdownNow be able to stop the accept() call? Because the api doc states that it is not guaranteed to succeed.
Please, feel free to point out any error/poor design choice that I've made. Ty
You can either close you connections manually (both client/server side) using the close() method or you can set a timeout.
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take
effect. If the timeout expires and the operation would continue to
block, java.io.InterruptedIOException is raised. The Socket is not
closed in this case.
Is this the right way to stop such a server?
As you say it is a server that means you should not need to stop it but in exceptional conditions.
As you state the shutdownNow() API says:
There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks.
I have the following code:
socket.connect(new InetSocketAddress(serverHost, serverPort), CONNECT_TIMEOUT);
The problem is that when the DNS is not accessible the InetSocketAddress takes 45sec to timeout and return an exception ("Host in not accessible...").
I need the entire command (so the creation of InetSocketAddress and the connect to timeout earlier. I did not find a way to make the new InetSocketAddress(serverHost, serverPort) timing out earlier.
Is it possible?
PS
I'm on Android but the problem is the same on other platform
There is no easy way. You need to run this code
socket.connect(new InetSocketAddress(serverHost, serverPort), CONNECT_TIMEOUT);
in a separate thread (i/o thread) and communicate with it from UI main thread. Once you are over your time limit - send it a terminate signal and proceeding in UI thread immediately, don't wait till it does terminate. Depending on the state, the i/o thread either dies immediately or eventually.
This question has no doubt been asked in various forms in the past, but not so much for a specific scenario.
What is the most correct way to stop a Thread that is blocking while waiting to receive a network message over UDP.
For example, say I have the following Thread:
public class ClientDiscoveryEngine extends Thread {
private final int PORT;
public ClientDiscoveryEngine(final int portNumber) {
PORT = portNumber;
}
#Override
public void run() {
try {
socket = new DatagramSocket(RECEIVE_PORT);
while (true) {
final byte[] data = new byte[256];
final DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
}
} catch (SocketException e) {
// do stuff 1
} catch (IOException e) {
// do stuff 2
}
}
}
Now, would the more correct way be using the interrupt() method? For example adding the following method:
#Override
public void interrupt() {
super.interrupt();
// flip some state?
}
My only concern is, is socket.receive() not a non-interruptable blocking method? The one way that I have thought of would be to implement the interrupt method as above, in that method call socket.close() and then cater for it in the run method in the catch for the SocketException. Or maybe instead of while(true) use some state that gets flipped in the interrupt method. Is this the best way? Or is there a more elegant way?
Thanks
The receive method doesn't seem to be interruptible. You could close the socket: the javadoc says:
Any thread currently blocked in receive(java.net.DatagramPacket) upon
this socket will throw a SocketException
You could also use setSoTimeout to make the receive method block only for a small amount of time. After the method has returned, your thread can check if it has been interrupted, and retry to receive again for this small amount of time.
Read this answer Interrupting a thread that waits on a blocking action?
To stop a thread, you should not user neither interrupt nor stop in java. The best way, as you suggested by the end of your question, is to have the loop inside the main method controlled by a flag that you can rise as needed.
Here is an old link about this :
http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
Other ways of stopping a thread are deprecated and don't provide as much control as this one. Also, this may have changed a bit with executor services, I didn't have time to learn much about it yet.
Also, if you want to avoid your thread to be blocked in some IO state, waiting for a socket, you should give your socket a connection and reading time out (method setSoTimeout).
Regards,
Stéphane
This is one of the easier ones. If it's blocked on a UDP socket, send the socket a UDP message that instructs the receiving thread to 'stop'.
Rgds,
Martin
I need a simple client-server communication in order to implement unit-test.
My steps:
Create server thread
Wait for server thread to put server socket into listen mode ( serverSocket.accept() )
Create client
Make some request, verify responses
Basically, I have a problem with step #2. I can't find a way to signal me when server socket is put to "listen" state. An asynchronous call to "accept" will do in this case, but java doesn't support this (it seems to support only asynchronous channels and those are incompatible with "accept()" method according to documentation).
Of cause I can put a simple "sleep", but that is not really a solution for production code.
So, to summarize, I need to detect when ServerSocket has been put into listen mode without using sleeps and/or polling.
The socket is put into listening state as soon as you construct the ServerSocket object, not when you call accept. As long as you create the client after the ServerSocket constructor has completed, you won't have a problem. Connections will be accepted and internally queued until accept gets called.
Here is some code to demonstrate:
ServerSocket serverSocket = new ServerSocket(12345);
Thread.sleep(10000);
Socket socket = serverSocket.accept();
During that 10 second gap before accept is called, the OS netstat command will show the server socket in "LISTENING" state, and clients can connect to it. If a client connects during that 10 seconds, the connection is queued, and when the accept method is finally called it immediately returns the queued Socket object.
Why not to send single just before calling accept()?
connectionAccepted = true;
loc.notify();
socket.accept();
To be sure that the socket is ready add a tiny sleep in your "client" code:
wait();
// we are here when notify is called.
Thread.sleep(10); // 10 ms
startTest();
You can even do better: create loop that tries to "ping" the socket with a tiny sleep between attempts. In this case you will start test as quickly as it is possible.
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 uses interrupt 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 a ServerSocketChannel. A server created with a ServerSocket 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 on accept, 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 for Socket 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.
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.
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() ?
If this thread is blocked in an I/O
operation upon an interruptible
channel then the channel will be
closed, the thread's interrupt status
will be set, and the thread will
receive a ClosedByInterruptException.
If this thread is blocked in a
Selector then the thread's interrupt
status will be set and it will return
immediately from the selection
operation, possibly with a non-zero
value, just as if the selector's
wakeup method were invoked.