如何在Java中立即识别出断开的套接字连接?

问题描述 投票:3回答:4

我有一个典型的Java客户端和服务器。客户端向服务器发送一些请求并等待响应。客户端从包含的输入流中读取100个字节的数据到一个字节数组中。它等待在指定的超时时间(例如3秒)内读取100字节的完整响应。这里的问题是在写入响应时/之前确定服务器是否发生故障或崩溃。基本上,我们需要确定套接字是否因为某些原因而断开或者对等端断开连接。有没有办法识别这个?

java sockets
4个回答
4
投票

如何在Java中立即识别出断开的套接字连接?

您无法使用Java或任何其他语言立即检测到它。 TCP / IP不知道,所以Java无法知道。检测TCP连接损坏的唯一可靠方法是写入并捕获IOExceptions,它们不会立即发生。


2
投票

标识连接的最佳方法是关闭连接。即,您希望在给定的时间内得到响应并标记该响应是否未按预期发生。

当您正常断开连接时(例如,另一端调用close()),一旦缓冲区耗尽,连接上的读取将通知您。

但是,如果出现其他类型的故障,则在操作系统超时(例如3分钟后)之前可能不会通知您,实际上,您可能希望保持连接。例如如果您将网络电缆拉出10秒钟并将其重新插入,则无需失败。

编辑:我认为在自动处理连接/服务“失败”方面过于激进是一个好主意。基于对真实原因的调查,通常可以通过对系统的计划修复来更好地处理。例如增加带宽,冗余连接,更快的服务器,代码修复。


1
投票

如果连接异常中断,你会在阅读时收到IOException;这通常发生得非常快,但不能保证时间 - 一切都取决于操作系统,网络硬件等。如果远程端正常关闭套接字,你将读取-1作为下一个字节。


0
投票

假设其他一切正常,如果远程对等方 - TCP服务器 - 被杀死,那么TCP客户端通常会收到TCP RST(重置),并且您将在客户端应用程序中获得IOException

但是,除了正在被杀死的进程之外,还有许多其他问题可能会出错。基本上两个进程之间的网络路径上的任何东西:电缆被拉扯,路由器死亡,防火墙死亡等等。所有这些都不会立即被检测到。

由于上述原因,一般规则是 - 正如EJP的答案所指出的那样 - 断开的连接只能通过写入来检测。这就是为什么始终建议TCP客户端和TCP服务器定期交换某种类型的心跳消息。有不同的方法来做到这一点。我最喜欢TCP客户端的方法 - 在没有从TCP服务器接收数据的情况下 - 向服务器发送心跳消息并期望在特定时间段内回复。这样,只有在真正需要时才会发送心跳消息。

一种次优的方法 - 如果你不能实现真正的心跳 - 就是总是以超时读取。设置timeout on the socket,然后抓住java.net.SocketTimeoutException。这将使您知道在x毫秒内没有在套接字上收到任何数据。

应该提到的是,有一种情况是您不必使用心跳,也不必使用套接字超时:如果TCP客户端和TCP服务器通过环回接口进行通信,则断开的连接将始终传播到TCP客户端应用程序和TCP服务器应用程序。这是因为,在这种情况下,两个进程之间实际上没有网络基础结构。因此,如果您的现有应用程序在其TCP通信方面没有很好的设计(即它没有实现某种形式的心跳或至少读取超时),那么作为最后的手段,您可以“修复”通过将两个应用程序移动到同一主机上并让它们通过环回接口进行通信来解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.