简体   繁体   English

Java TCP / IP套接字如何向应用程序报告传输成功或失败?

[英]How do Java TCP/IP sockets report transmission success or failure to the application?

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. 我在使用Java TCP / IP套接字时遇到问题:即使在此期间服务器关闭(没有正确的TCP / IP断开连接),我的Java应用程序也将不断向服务器发送数据。

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: 另一个Stack Overflow问题中 ,我找到了以下答案:

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. TCP / IP(以及Java套接字)将确保您最终成功发送数据或获得错误(对于Java除外)。

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? 我的代码是否足以通知TCP / IP堆栈而无法成功发送我的字符串,或者我是否需要做其他事情?

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. 它不能令人满意地回答我的问题,我只能添加一个新答案,而不能添加新评论。

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. 您可能有两个问题: PrintWriter是Java Stream / Reader / Writer中的一头Writer ,因为它吞噬了异常并要求您显式检查错误。

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). 对此的唯一用途(在我看来)是标准流( System.outSystem.err ),其中写输出失败不应停止应用程序(例如,如果没有标准输出可用)。

Replace that with an OutputStreamWriter and you'll be informed about errors as soon as Java knows about them. OutputStreamWriter替换它,一旦Java知道了错误,就会通知您。

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. 这给我带来了第二个可能的问题:TCP / IP没有任何自动的保持活动数据包:因此, 如果您的连接以某种方式被切断,则在尝试发送数据之前您实际上不会注意到它。

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. 这是TCP / IP协议固有的,不是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. 如果要减少问题,则可以发送定期的保持活动/ ping消息,但没有实际效果,只是它们会检查连接是否仍然有效。

Your question is different enough I'd say. 我会说你的问题足够不同。 Google has a lot to say about this sort of thing though. Google对于这类事情有很多话要说。 The keep-alives ( SO_KEEPALIVE ) are not designed for this sort of thing. 保持活动( SO_KEEPALIVE )并非针对此类情况而设计。 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. 从我读了TCP规范说他们应该超过每两小时一次发送,它是由你的操作系统来管理它,所以你没有太多的控制权。 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). 如果直接使用SocketOutputStream ,则在尝试发送到不可用的目的地时(无论出于何种原因),它将引发异常。 Since you are using PrintWriter , you need to check for errors manually using checkError() . 由于使用的是PrintWriter ,因此需要使用checkError()手动检查错误。

So, in summary: Yes, it is sufficient for your purpose. 因此,总而言之:是的,它足以满足您的目的。

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. 我没有提到(因为当时我认为它不相关)是我正在尝试在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. 经过几周的测试,Android似乎对标准Java网络类的实现与Oracle JRE的行为却大不相同。 On Android, it is apparently impossible to reliably detect if the connection has been closed, even if I closed it myself. 在Android上,即使我自己关闭了连接,显然也无法可靠地检测连接是否已关闭。 [Stream].write() will try writing for several minutes. [Stream].write()将尝试写入几分钟。 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. 因此,在Android上,似乎总是需要发送自己的保持活动状态(并检查接收状态!)才能检测到断开的连接。

The other answers to this question will work fine with the Oracle JRE. 该问题的其他答案将与Oracle JRE配合使用。 Thanks again! 再次感谢!

If anyone can provide further information on this topic, please do so. 如果有人可以提供有关此主题的更多信息,请这样做。

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. 根据您的操作系统,有多种方法可以更改保持活动测试间隔。

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. 根据您设置的套接字opt SO_LINGER (请参阅本文 ), close()调用将立即返回或等待,直到所有挂起的TCP传输成功或发生错误为止,然后由close()引发IOException来发出信号close()实施。

Also SO_TIMEOUT has an effect on when retries will time out. SO_TIMEOUT也影响重试何时超时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM