How to properly close a socket after an exception is caught? - java

After my last project I had the problem that the client was expecting an object from the server, but while processing the clients input an exception that forces the server to close the socket for security reasons is caught.
This causes the client to terminate in a very unpleasant way, the way I decided to deal with this was sending the client a Input status message after each recieved input so that he knows if his input was processed properly or if he needs to throw an exception.
So my question:
Is there a better/cleaner way to close the socket after an exception is caught?

If I understand correctly you have already closed the socket from the server side, and you need your client to realize this and handle the error accordingly.
Take a look at the Socket documentation and in particular the setSoTimeout method. For example, if the timeout is set to 5 seconds and the client attempts to read from the server socket and he does not get an answer, then the timeout expires and a java.net.SocketTimeoutException is raised and you can catch it and close the socket.
You could also use a ScheduledExecutorService or a Timer to simulate the timeout.

For things like this:
Make sure to put this socket code within a try/catch block.
Close the socket within a 'finally'. That way you ensure that you cleanly close the socket whether there is an exception or not.

Incorrect. That exception only occurs when you try to use a socket you have closed yourself.
What the OP should be looking for is EOFException, or IOException: 'connection reset', or a SocketTimeoutException.

You really can't since the socket is closed, you could listen on the client for
java.net.SocketException: socket closed
and then you would know that you lost a connection to the server.

Related

socket.isConnected() does not detect disconnected socket [duplicate]

This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 1 year ago.
I have a Java application that connects to a service using a socket. I always expect to receive something from that socket, and if it disconnects I need to reconnect. Reconnect works fine when I close/open socket from remote application side in normal way. But when the remote application is killed, my Java application does not detect that. I run the thread with:
if (socket.isConnected()) { /* code */ }
This function does not detect when the socket is killed. Why? How to detect that remote socket is killed?
Note: I must use java 1.4
UPD
I do reading from socket input stream acording loggic:
if (in.available()) {...}
This not detects socket is disconnected. Should I use in.read() even if no data available to detect closed socket?
The various isXXX() methods of Socket don't track the actual state, but what has been done to the socket. For example isConnected() will return true even after a socket has been closed, if it has been connected at some point.
The only way to detect if a Socket is still valid is to try to use it, i.e. read or write to it. If an exception is thrown, you need to clean up and reconnect.
This function does not detect when the socket is killed. Why?
These functions only tell you the current state of the Socket object: they don't actively test the line. isConnected() means 'have I ever connected?'.
How to detect that remote socket is killed?
You need to read a message from the connection with an appropriate timeout. If the connection is closed or lost you eventually get an IOException, or a timeout will be reached.
BTW To save error messages, I suggest you send a message indicating a graceful disconnect before closing. This way graceful disconnects can be treated differently to connection failures in term of logging.

Socket is closed on write stream but not when reading

I recently noticed in my multi threaded Java socket handler that I was getting exceptions when I tried to write on a socket, however I was still receiving data via reads. It was my understanding that if the socket was closed the input stream reader would also throw a socket closed exception when attempting the next read. Is this not the case and should I manually close the socket if I get this exception when attempting to write?
A TCP connection can be closed in the write direction but not in the read direction, such a connection is called "half closed". You should keep reading the rest of the data the other side sent, otherwise the connection will not close normally.
If you think about it, how else could you sanely shut down a TCP connection? If you shut it all the way down in one step, what happens if the other side sends some data to you before you finish shutting it down? You still need to receive it. But, obviously, you can't keep sending data.

Does SocketChannel.close() close the socket also?

I have a server program that needs to close any connections that remain when the server is shutting down. I know I need to call SocketChannel.close(). My question is if I also need to close the Socket associated with the SocketChannel or if SocketChannel.close() does that automatically.
Of course it closes the socket. What else would it be for? The only exception is when the channel is registered with a Selector, when the actual close is deferred to the next select operation.
SocketChannel.close() should close the Socket. However, there have been some bugs around this issue (should have been solved a long time ago). http://bugs.sun.com/view_bug.do?bug_id=4960962. Another situation that can cause problems: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6179351

Netty socket.shutdownOutput() equivalent to avoid TCP RST?

I am wondering if there is a way to avoid having a TCP RST flag set as opposed to a TCP FIN flag when closing a connection in Netty where there is input data remaining in the TCP receive buffer.
The use case is:
Client (written in C) sends data packets containing many fields.
Server reads packets, encounters an error on an early field, throws an exception.
Exception handler catches the exception, writes an error message, and adds the close on write callback to the write future.
The problem is:
Remaining data in the receive buffer causes Linux (or Java..) to flag the TCP packets with the RST flag. This prevents the client from reading the data since when it gets around to trying it finds it has a read error due to the socket being closed.
With a straight Java socket, I believe the solution would be to call socket.shutdownOutput() before closing. Is there an equivalent function in Netty or way around this?
If I simply continue reading from the socket, it may not be enough to avoid the RST since there may or may not be data in the buffer exactly when close is called.
For reference: http://cs.baylor.edu/~donahoo/practical/CSockets/TCPRST.pdf
UPDATE:
Another reference and description of the problem: http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html
Calling shutdownOutput() should help with a more orderly closing of the connection (by sending a FIN), but if the client is still sending data then RST messages will be sent regardless (see answer from EJP. A shutdownOutput() equivalent may be available in Netty 4+.
Solutions are either to read all data from the client (but you can never be sure when the client will fully stop sending, especially in the case of a malicious client), or to simply wait before closing the connection after sending the response (see answer from irreputable).
If you can get hold of the underlying SocketChannel from Netty, which I am no expert about, you can call channel.socket().shutdownOutput().
Remaining data in the receive buffer causes Linux (or Java..) to flag
the TCP packets with the RST flag. This prevents the client from
reading the data since when it gets around to trying it finds it has a
read error due to the socket being closed.
I don't understand this. TCP guarantees that the client will receive all the data in its socket receive buffer before he gets the FIN. If you are talking about the server's socket receive buffer, it will be thrown away by the close(), and further attempts by the client to send will get an RST which becomes an IOException: connection reset', because there is no connection to associate it with and therefore nowhere to put it. NB It is TCP that does all this, not Java.
But it seems to me you should read the whole request before closing the channel if it's bad.
You could also try increasing the socket receive buffer so it is big enough to hold an entire request. That ensures that the client won't still be sending when you want to close the connection. EDIT: I see the request is megabytes so this won't work.
Can you try this: after server writes the error message, wait for 500ms, then close(). See if the client can receive the error message now.
I'm guessing that the packets in the server receive buffer have not been ACK-ed, due to TCP delayed acknowledgement. If close() is called now, the proper response for these packets is RST. But if shutdownOutput() is invoked, it's a graceful close process; the packets are ACK-ed first.
EDIT: another attempt after learning more about the matter:
The application protocol is, the server can respond anytime, even while the client request is still being streamed. Therefore the client should, assuming blocking mode, have a separate thread reading from server. As soon as the client reads a response from server, it needs to barge into the writing thread, to stop further writing to the server. This can be done by simply close() the socket.
On the server side, if the response is written before all request data are read, and close() is called afterwards, most likely RST will be sent to client. Apparently most TCP stacks send RST to the other end if close() is called when the receive buffer isn't empty. Even if the TCP stack doesn't do that, very likely more data will arrive immediately after close(), triggering RST anyway.
When that happens, the client will very likely fail to read the server response, hence the problem.
So the server can't immediately close() after response, it needs to wait till client receives the response. How does the server know that?
First, how does the client know that it has received the full response? That is, how is the response terminated? If response is terminated by TCP FIN, the server must send FIN after response, by calling shutdownOutput(). If the response is self-terminated, e.g. by HTTP Content-Length header, the server needs not to call shutdownOutput().
After the client receives the full response, per protocol, it should promptly quit sending more data to the server. This is done by crudely sever the connection; the protocol didn't design a more elegant way. Either FIN or RST is fine.
So the server, after writing the response, should keep reading from the client, till EOF or error. Then it can close() the socket.
However, there should be a timeout for this step, to account for malicious/broken clients and network problems. Several seconds should be sufficient to complete the step in most cases.
Also, the server may not want to read from the client, since it isn't free. The server can simply wait past the timeout, then close().

Writing to SocketChannel in CLOSE-WAIT

I noticed that SocketChannel.write does not throw any exception, when the underlying connection is in CLOSE-WAIT state. Is it expected behaviour? If so, how can I figure out that the connection is not ESTABLISHED?
It shouldn't throw an exception the first time. The connection may still be writable. CLOSE_WAIT means that an incoming FIN has been received. All that means is that the other end has finished writing. It may still be reading: it may only have shutdown the connection for output. So TCP has to write the data. If the peer has closed the entire connection, it will issue an RST on receipt of the write, which you will experience as a connection reset on a subsequent write.
Your application protocol should be such that either writing to a connection closed by the peer is impossible, or else that multiple writes may be done before an error shows up. TCP cannot possibly give you an error on the first such write.

Categories