Java - closing a ServerSocket without Exceptions? - java

For years I've been wondering what the correct way to close a listening ServerSocket in Java is. My implementations always work like this, they:
Create a new ServerSocket(int).
Start a thread that calls its accept() method in a while (true) loop.
Start another thread when accept() returns (client connects) that reads from the client until it disconnects. The accept thread then continues with another accept() call.
But when I want to close the ServerSocket because my application is exiting, I've never found another way of doing so other than calling it's close() method (after I've closed all client Sockets), which causes accept() to throw a SocketException, I catch that and break from the while (true) loop in the accept thread, causing all my threads to exit.
I think this is ugly, strictly speaking there is no exception occurring, closing my ServerSocket is part of my programs normal operation.
Is there really no other way of doing this without causing an Exception to be thrown?
Thanks.

I've never found another way of doing so other than calling it's close() method (after I've closed all client Sockets),
You can set a flag closed = true; and open a dummy connection to wake up the accept()ing thread which checks the flag before continuing.
which causes accept() to throw a SocketException,
A SocketClosedException which is expected behaviour here.
I catch that and break from the while (true) loop in the accept thread,
If you catch it outside the loop, you don't need to also break out of the loop. If the exception is thrown and you have set closed = true you can discard the exception.
BTW I would do
while(!serverSocket.isClosed()) {
causing all my threads to exit.
There is no particular reason you need to have this, but you can choose to do this if you want.
I think this is ugly, strictly speaking there is no exception occurring,
An exceptional condition is happening. What is not happening is an Error.
closing my ServerSocket is part of my programs normal operation.
Or you could say it is operating normally when it is running and not shutting down.

Thanks for your comment.
You can set a flag closed = true; and open a dummy connection to wake up the accept()ing thread which checks the flag before continuing.
Opening a new Socket to close an existing one? IMO that is one of the worst sins ever.
A SocketClosedException which is expected behaviour here.
Actually it doesn't throw a SocketClosedException but a SocketException, the following code:
try {
final ServerSocket ss = new ServerSocket(1234);
new Thread(new Runnable() {
#Override
public void run() {
try {
ss.accept();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
ss.close();
} catch (Exception ex) {
ex.printStackTrace();
}
Produced the following output:
java.net.SocketException: Socket is closed
at java.net.ServerSocket.accept(ServerSocket.java:494)
at Main$1.run(Main.java:12)
at java.lang.Thread.run(Thread.java:744)
If you catch it outside the loop, you don't need to also break out of the loop. If the exception is thrown and you have set closed = true you can discard the exception.
BTW I would do
while(!serverSocket.isClosed()) {
That would work, but I think this should work without setting flags and catching Exceptions.
An exceptional condition is happening. What is not happening is an Error.
Or you could say it is operating normally when it is running and not shutting down.
I don't agree. It is normal behaviour for applications to be exiting. They may always do so.
Why doesn't the accept() method just returns null when close() is called? That would be so much easier.

Related

While true loop being broken by a try/catch in Java

I am a beginner to networking and am working on implementing it in a game i have, it is mostly working but in the client my loop receiving packets is stopping ant a try catch. here is the code:
public void run() {
while(true){
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
}catch(IOException e){
e.printStackTrace();
}
this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
}
}
After debugging i have found that the loop is not getting past the try catch statement.(but the try is being activated once seemingly with no error).
First of all your loop condition that you provided is not a variable, You have directly used a boolean valued true . It might a situation of infinite-loop.
while(true){..... // yourCode ....}
Your loop will continue even if socket.receive(packet); line raise an IOException because this exception is handled by the catch() block.
it means it will execute till any exception raised at this line
this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
Now, Your problem is this method public void receive(DatagramPacket p) actually method will work till datagram is received but your loop will continue till exception is raised till this.parsePacket() method raised an Exception.
So, please change your conditional statement such that if datagram is no more present then loop must be terminated.
As per java-docs for the method public void receive(DatagramPacket p)
This method blocks until a datagram is received.
The thread executing the flow gets blocked [waits until the datagram is received]. Your loop is not broken its just in halt state.
Loop will be broken in case of some exception occurs which is not caught and handled in side the body of the loop.
Also there is little suggestion I would like you to implement in your code. You should not run an infinite loop. Instead of using true you can try using Thread.currentThread().isInterrupted() and when your game ends you can call interrupt() on the Thread responsible for executing the code flow of the loop. Also if in case of IOException you wish to retry (may be in retry resources are in order and you do not get the exception) then putting catch inside the loop is O.K. else you can move the catch outside the loop, it depends on your need and flow. You can probably put a counter for number of retries.

Java Client Server - Exception Handling (Thread)

I wonder how to handle exceptions correctly within a client server application. My client sends an information to the server(thread) which receives it within its run method.
I have already read something about uncaught exception handling when dealing with exceptions in the run method but want to know if this is the correct way to do it in my case.
I want to catch the exception on the client side.
I have in mind to do the following:
//Server
run(){
try{
...
}
catch(Exception e){
clientoutputstream.write(...); //transmitting the error
}
}
Any other suggestions?
You should put a try { } catch (IOException) around your read() call so you know if the other end has closed the connection. The other thing you might want to do is to put a try { } catch(Throwable) { } around the processing code so you can manually close the socket (Be very careful about catching Throwable) But if you just let the thread die the Socket will be closed when the object is garbage collected or when it times out

Should I close the socket if setSoTimeout throw an exception?

Should i close the socket in finally block after setSoTimeout throws an Exception
try {
socket.setSoTimeout(4000);
//code for reading
} catch(java.lang.Exception ex) {
System.out.println(ex.toString());
} finally {
socket.close(); <-------is it necessary?
}
It depends on the actual exception, but you shouldn't write this method like this. The way you've written it, you will always close the socket. The close should be in the catch block, not the finally block.
Yes it is necessary.
Once a socket has been closed, it is not available for further networking use (i.e. can't be reconnected or rebound). A new socket needs to be created,
Closing this socket will also close the socket's InputStream and OutputStream.
you are probably thinking that when an exception is thrown the socket's resources are freed, but that isn't the case since socket.isClosed(); returns false if the exception is thrown, and generally always close the resource in the finally block because you don't really know whether an exception will be thrown or not, and its a good programming practice.

shutdown TCP thread server

I coded a little TCP thread Server, which creates a new thread for every server.accept(). Nearly everything works great, but I have problems to kill all threads per interrupt. (I use a ServiceExecutor to manage the threads. Therefore I use the shutdownNow method to reach the interrupt-methods) The Worker-instances use a BufferedReader and it's readline-method to receive and compute the input. AFAIK the readline blocks and would not react on an interrupt, but how to stop it?
while(!isInterrupted()){
try {
clientSocket = this.serverSocket.accept();
} catch(IOException e){
break;
}
this.threadPool.execute(new ThreadWorker(clientSocket));
}
threadPool.shutdownNow();
try{
serverSocket.close();
}catch(IOException e){
//todo
}
I tried to close the ServerSocket to kill the Input/Output Streams, but it didn't work as expected.
A couple alternatives:
1) If you are closing the whole app, and there is nothing of importance to explicitly close, call System.Exit(0). HEALTH WARNING - doing this causes some developers to have apoplectic fits and post endlessly about 'cleaning up gracefully'.
2) Keep a thread-safe list of all client sockets in the accept() thread. Pass a reference to this list as part of your client context that is passed to the client<>server threads. Add new connections to the list in the accept() thread. When a client thread detects a disconnect, remove its entry from the list. When you want to close all clients, iterate the list and close the client sockets - this will cause the readline method to return early, with an error, in the client threads.

How to interrupt a thread if it is to open socket?

I have tried to close the current thread that is a part of multi-threading server.
The thread is ready to open the socket that may be accessed by clients.
Everything works fine except when the code below is contained in while() loop.
new ServerThread(serversocket.accept(), this.Rstr,
bag.numberofDatatoAcquire).start();
Here is the code for the server:
public void run() {
System.out.println("This has been called ");
try{
System.out.println("This has been tried");
serversocket = new ServerSocket(this.iPort);
Thread thisThread = Thread.currentThread();
while(!thisThread.isInterrupted()){
new ServerThread(serversocket.accept(), this.Rstr, bag.numberofDatatoAcquire).start();
//sending socket accessed, where it will store the data and how much it will collect it.
System.out.println("This has been running");
Thread.sleep(10);
}
}catch(InterruptedException e){
//why bother? it is an usual happening...lol
}catch(IOException ioe)
{
System.err.println("Can't open the socket on port");
}
finally{
System.out.println("Thread is dead and ready for change");
}
}
And this is a part of GUI events: this works well without "new ServerThread..." code.
private OverWatch EW = new OverWatch(bag.iPortOrder, bag.SessionAcquisitionSavingDirectory);
....
private void OverWatcherControl(boolean checker)
{
if(checker)
EW.start();
else
EW.interrupt();
}
Since the variable bag.numberofDataToAcquire (public integer type) is supposed to be changed whenever user wants, I think I have to stop this thread and change the variable then run this thread again. Am I wrong? Or how can I interrupt this thread?
Thanks,
ServerSocket.accept() is a blocking call that is not responsive to thread interruption. Almost all the java.net blocking calls (connect, read, accept, etc) do not respond to Thread.interrupt(). This behavior is "as designed".
A way to wake up a thread blocked in .accept() or .read() is to close the underlying socket.
Alternatively you could set SO_TIMEOUT (setSoTimeout) on the ServerSocket, which will cause .accept() to wake up periodically by throwing a SocketTimeoutException. You could catch that exception and use it as an opportunity to check the interrupt status on the thread.
The java.nio package (Java 1.4+) provides an alternate sockets API that is more responsive to interruption.
Just as an alternative to using a timeout or killing the socket:
Fake a new connection to the socket. This will "wake up" the accept() and then an additional signaling mechanism (e.g. flag or interrupt check) can be used (although the logic would have to be altered slightly from shown to not "lie" in the println).
I have used this approach before and it worked well: no need to wait for a timeout (even a sort one) or handle another exception and the socket remains open/valid (which may or may not be desired). On the other hand, I'm not sure what would happen on a really long/broken TCP handshake, but that's a case I never encountered ;-)
Happy coding.
I initially answered it using the serverSocket.setSoTimeout(millis) and handling the SocketTimeoutException. See below.
A better way to do it would be to use ServerSocketChannel which gets interrupted in the accept() call when you call thread.interrupt() so you don't have to spin at all. So you'd do something like:
ServerSocketChannel socketChannel = ServerSocketChannel.open();
socketChannel.socket().bind(new InetSocketAddress(this.iPort), 10);
...
while (! thisThread.isInterrupted()) {
// channel accepts _are_ interrupted by the call to thread.interrupt()
// it throws ClosedByInterruptException when interrupt() is called
SocketChannel accepted = socketChannel.accept();
new ServerThread(accepted.socket(), this.Rstr,
bag.numberofDatatoAcquire).start();
}
I'll take a whack at explaining the code:
while(!thisThread.isInterrupted()){
new ServerThread(serversocket.accept(), this.Rstr,
bag.numberofDatatoAcquire).start();
Thread.sleep(10);
}
I think your problem here is that serversocket.accept() hangs waiting for a socket to be accepted. From the accept() javadocs:
Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.
You need to set a timeout on your socket before the while loop. You can use setSoTimeout(millis) for that.
serversocket.setSoTimeout(10000);
This will then throw a SocketTimeoutException if it times out. Then you won't need the Thread.sleep(10) (which is for 10ms btw) because the sleeping will be done inside of the accept() method. I would not recommend accept(10) because that would spin pretty aggressively.

Categories