How do Java TCP/IP sockets report transmission suc

2019-05-01 11:50发布

问题:

I am having a problem with Java TCP/IP sockets: my Java application will continue endlessly to send data to a server even if the server gets switched off (without a proper TCP/IP disconnect) in the meantime.

I am using the following code to send the data:

PrintWriter out = PrintWriter(socket.getOutputStream(), true);
out.write("text");

if (out.checkError()) {
   System.err.println("Error sending string!");
}

In another Stack Overflow question, I found the following answer:

TCP/IP (and therefor java sockets) will guarantee that you either successfully send the data OR get an error (exception in the case of java) eventually.

Is my code sufficient for getting informed about the TCP/IP stack not being able to successfully send my string or do I need to do something additionally?

Btw: was it correct to open a new question even though the other question was similar? It did not answer my question satisfactorily and I was only able to add a new answer, not a new comment.

回答1:

You might have two problems: PrintWriter is a strange beast in the Java Stream/Reader/Writer world in that it swallows exceptions and requires you to explicitly check for errors.

The only use for this (in my opinion) are the standard streams (System.out and System.err), where failure to write output should not halt the application (for example if no standard output is available).

Replace that with an OutputStreamWriter and you'll be informed about errors as soon as Java knows about them.

That brings me to the second possible problem: TCP/IP doesn't have any automated keep-alive packets: so if your connection gets severed in some way, you won't actually notice it until you attempt to send data.

So if you connect to some socket, send some packets, wait a bit and then get disconnected, you will only be notified of the fact when you next try to send some data. This is inherent in the TCP/IP protocol and not the fault of Java.

If you want to reduce the problem, then you could send periodic keep-alive/ping messages with no actual effect, except that they check if the connection is still alive.



回答2:

Your question is different enough I'd say. Google has a lot to say about this sort of thing though. The keep-alives (SO_KEEPALIVE) are not designed for this sort of thing. From what I have read the TCP spec says that they should not be sent more than once every two hours and it is up to your OS to manage it so you don't have much control. I emphasize from what I have read.

Whether you can use them more than once every two hours doesn't matter in your case though since you are continually sending data. Keep-alives are only needed if you want to detect a broken connection while you are not sending data.

If you were using the OutputStream of the Socket directly, it would throw an exception when you attempt to send to an unavailable destination (for whatever reason that may be). Since you are using PrintWriter, you need to check for errors manually using checkError().

So, in summary: Yes, it is sufficient for your purpose.



回答3:

What I didn't mention (as I thought it was not relevant at that time) is that I am trying to do this on Android.

After several weeks of testing, though, it seems that Android's implementation of the standard Java networking classes is behaving very differently from the Oracle JRE. On Android, it is apparently impossible to reliably detect if the connection has been closed, even if I closed it myself. [Stream].write() will try writing for several minutes. So on Android, it appears that you will always need to send your own keep-alives (and check for reception!) for detecting a broken connection.

The other answers to this question will work fine with the Oracle JRE. Thanks again!

If anyone can provide further information on this topic, please do so.



回答4:

Sometimes even though the server has died, your client application is not informed about it. Usually this is a bad router somewhere failing to shut down both sides of the connection. You should set up keep-alives so you can detect this kind of failure.

Depending on your OS there are ways to change the keep-alive test interval.



回答5:

One special condition applies when you are closing the socket. Depending on the socket opt SO_LINGER (see this article) you set, the close() call will either return immediately or wait until all pending TCP transmissions were either successful or an error occured, which is then signalled by an IOException thrown from the close() implementation.

Also SO_TIMEOUThas an effect on when retries will time out.