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

我遇到了Java TCP / IP套接字的问题:我的Java应用程序将无休止地继续将数据发送到服务器,即使服务器在此期间关闭(没有正确的TCP / IP断开连接)。

我使用以下代码发送数据:

PrintWriter out = PrintWriter(socket.getOutputStream(), true); out.write("text"); if (out.checkError()) { System.err.println("Error sending string!"); } 

在另一个Stack Overflow问题中 ,我找到了以下答案:

TCP / IP(及其java套接字)将保证您成功发送数据或最终获得错误(在java的情况下例外)。

我的代码是否足以让我们了解TCP / IP堆栈无法成功发送我的字符串或我是否需要另外做一些事情?

顺便说一句:即使另一个问题相似,打开一个新问题是否正确? 它没有令人满意地回答我的问题,我只能添加一个新的答案,而不是一个新的评论。

您可能有两个问题: PrintWriter在Java Stream / Reader / Writer世界中是一个奇怪的野兽,它吞下exception并要求您明确检查错误。

对此(我认为)的唯一用途是标准流( System.outSystem.err ),其中写入输出失败不应该停止应用程序(例如,如果没有可用的标准输出)。

OutputStreamWriter替换它,一旦Java知道它们就会被告知错误。

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

因此,如果您连接到某个套接字,发送一些数据包,等待一段时间然后断开连接,您只会在下次尝试发送一些数据时收到通知。 这是TCP / IP协议中固有的,而不是Java的错误。

如果您想减少问题,那么您可以发送定期的keep-alive / ping消息,但没有实际效果,除了它们检查连接是否仍然存在。

我的问题就是你的问题不同了。 谷歌对这类事情有很多话要说。 保持活动( SO_KEEPALIVE )不是为这类事物而设计的。 从我所看到的TCP规范说,它们应该每两个小时发送一次以上,并且由你的操作系统来管理它,所以你没有太多的控制权。 我从我所读到的内容中强调。

由于您不断发送数据,因此在您的情况下,您是否可以每两个小时使用它们并不重要。 只有在您不发送数据时才想检测断开的连接时,才需要保持活动。

如果您直接使用SocketOutputStream ,当您尝试发送到不可用的目标时(无论出于何种原因),它将抛出exception。 由于您使用的是PrintWriter ,因此需要使用checkError()手动检查错误。

因此,总结:是的,它足以满足您的需求。

我没有提到的(因为我认为当时没有相关性)是我试图在Android上这样做。

但经过几周的测试,似乎Android的标准Java网络类的实现与Oracle JRE的行为有很大不同。 在Android上,即使我自己关闭连接,显然也无法可靠地检测连接是否已关闭。 [Stream].write()会尝试写几分钟。 因此,在Android上,您似乎总是需要发送自己的保持活动(并检查接收!)以检测断开的连接。

对于这个问题的其他答案将适用于Oracle JRE。 再次感谢!

如果有人可以提供有关此主题的更多信息,请执行此操作。

有时即使服务器已经死亡,您的客户端应用程序也不会被告知。 通常这是一个糟糕的路由器,无法关闭连接的两侧。 您应该设置保持活动,以便检测此类故障。

根据您的操作系统,有一些方法可以更改保持活动测试间隔。

关闭套接字时适用一个特殊条件。 根据您设置的套接字选项SO_LINGER (请参阅此文章 ), close()调用将立即返回或等待所有挂起的TCP传输成功或发生错误,然后通过从close()抛出的IOException发出信号close()实施。

SO_TIMEOUT也会影响重试何时超时。