Writing to SocketChannel in CLOSE-WAIT - java

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.

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.

ObjectInputStream.readObject() does not throw an exception when disconnected

I'm using a ObjectStream over a TCP connection to send data from a client to a server. Sometimtes the client is terminated while the server still waits for new data. In these cases readObject() is staying blocked without of throwing a Exception and my computation stops.
How can i determine if the ObjectStream is disconnected or only waiting for more data?
Using a timeout is difficult because of long delays between communication.
The only safe way is to use a timeout. I suspect the long delay you are seeing in detecting a disconnect is due to the nature of the network you have.
Is it really a problem if computation of a dead connection has stopped. This may waste resources for a short period but you should detect a failure within minutes and clean resources then.

Network listener in Java

I want to check when the internet goes off can i capture that event .I am not getting the proper API or any example which would explain the same .
I am using socket for (TCP)communication and I open a socket when the network is available. I have observed that the socket does not give any exception in case the network goes off.
If any one had done or any example links would be really helpful Thanks in advance
The problem is that no event 'network down' exists in tcp connections, they just go down.
As suggested by Jerome you should check if timeout is reached.
Of course if network goes down you won't receive packets neither be able to send them so the underlying InputStream and OutputStream will throw an IOException but just when they'll realize that network is not working properly (usually 2*rtt = 120 seconds, it depends how TCP layer is managed).
Look state diagram by yourself:
What typically happens is that when in ESTABLISHED your socket will send data over the socket while waiting for ACK from destination. ACK won't come since network went off so your socket's window fills up and socket starts resending packets until real timeout intervenes throwing the exception.
Another case is when network goes off and your socket realizes that it cannot write anymore on channel: it will throw an exception imediately upon calling outStream.write(...).
It's not that easy to tell whether the network is off or just slow.
If you set Timeouts, it will throw exception if it takes too long:
For sockets:
socket.setSoTimeout(CONNECTION_TIMEOUT);
For HttpURLConnections:
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setConnectTimeout(CONNECTION_TIMEOUT);
con.setReadTimeout(CONNECTION_TIMEOUT);
TCP is designed to be quiet when idle. There is no administrative packets on wire when there is no pending packet. If the connection is dead while idle, you will not know, no matter what the setting of the timeout is. It does have keepalives but it's pretty much useless at the recommended frequency of 2 hours and longer.
You need to build some heartbeat or keepalive in your application protocol to detect stale connections. Keepalive is nothing but a noop packet sent at regular interval to trigger TCP timeout when connection is down. In my app, I do this every 10 seconds.
Why don't you try pinging www.google.com
See http://java.sun.com/j2se/1.5.0/docs/guide/nio/example/Ping.java

Socket not disconnecting when connectivity changes

My chat application connects to a server and information is sent/received by the user. When the connection changes, such as 3g->wifi, wifi->3g, losing a data connection, etc, the socket sometimes stays connected for ages before disconnecting. During this time, it's impossible to tell if the connection is still active, it seems as if messages are being sent just fine. Other times, when sending a message, it will throw an IO error and disconnect.
Apart from implementing code to detect connection changes and reconnecting appropriately, is it possible to have the socket immediately throw an IO exception when connectivity changes?
Edit: I'm connecting using the following code:
Socket sock = new Socket();
sock.connect(new InetSocketAddress(getAddress(), getPort())), getTimeout());
//get bufferedReader and read until BufferedReader#readLine() returns null
I'm not using setSoTimeout as data may not be transferred for long periods of time depending on the remote server's configuration.
Are you talking about a java.net.Socket connection? Then try setSoTimeout(). Otherwise specify how you're connecting.
This is an old problem that I've seen a few times before in the database world.
The solution I used there was to manage the connection at the application level. I'd explicitly send a no-op message of some sort (i.e. SELECT 1 WHERE FALSE) over the connection every so often as a ping, and if this failed I would tear down and re-establish the connection, possibly to a failover server if the original wasn't accepting connections.
As previous answers already pointed out, this is a common problem. Even after sending a custom "ping" it might need some time until the socket realizes that the underlying connection is broken. Plus, regular pings are quite energy-demanding using 3-4G mobile networks, due to their tail states. Don't do that!
What you can do, however, is requesting to get informed when the connectivity changes (last section), and close/reconnect the socket manually in the according broadcast receiver. (EDIT: I see you already found out about this; just keeping it here for completeness)

Categories