我们的移动设备和服务器之间都有一个简单的客户端服务器架构,都是用Java编写的。一个非常简单的ServerSocket和Socket实现。然而,一个问题是当客户端突然终止(没有正确关闭套接字)时,服务器不知道它已断开连接。此外,服务器可以继续写入此套接字而不会出现任何异常。为什么?
根据文档,如果您尝试写入另一端无法访问的套接字,Java套接字应该抛出异常!
答案 0 :(得分:2)
最终将通过Retransmit Timeout(RTO)超时连接。但是,RTO是使用基于网络延迟(RTT)的复杂算法计算的,请参阅此RFC,
http://www.ietf.org/rfc/rfc2988.txt
所以在移动网络上,这可能是几分钟。等待10分钟,看看是否可以暂停。
解决此类问题的方法是在您自己的应用程序协议中添加心跳,并在未获得心跳确认时断开连接。
答案 1 :(得分:1)
这里的关键词(without closing the socket properly)
。
应始终以这种方式获取和处理套接字:
final Socket socket = ...; // connect code
try
{
use( socket ); // use socket
}
finally
{
socket.close( ); // dispose
}
即使采取此预防措施,您也应指定特定于协议的应用程序超时。
我的经验表明,遗憾的是,您无法可靠地使用任何套接字超时功能(例如,写操作没有超时,甚至读取操作有时可能永远挂起)。
这就是为什么你需要一个看门狗线程来强制你的应用程序超时并处理一段时间没有响应的套接字。
一种方便的方法是通过java.nio中的相应通道初始化Socket和ServerSocket。这种套接字的主要优点是它们是可中断的,这样你就可以简单地中断执行套接字协议的线程,并确保套接字正确处理掉。
请注意,您应该在双方强制执行应用程序超时,因为当您遇到无响应的套接字时,这只是时间问题和运气不好。
答案 2 :(得分:0)
TCP / IP通信可能非常奇怪。 TCP将在堆栈的底层重试相当长一段时间,而不会让上层知道发生了什么。
我完全可以期待在一段时间后(30秒到几分钟)你会看到一个错误,但我没有测试过这个我只是关闭TCP应用程序的工作方式。
您可能能够收紧TCP规范(重试,超时等),但又一次,没有太多搞乱。
另外,可能是我完全错了,你正在使用的Java实现只是不稳定。
答案 3 :(得分:0)
要回答问题的第一部分(关于不知道客户端突然断开连接),在TCP中,在尝试使用连接之前,您无法知道连接是否已经结束。
guaranteed delivery in TCP的概念非常微妙:实际上并未向另一端的应用程序保证交付(这取决于真正的保证方式)。 Section 2.6 of RFC 793 (TCP)提供了有关此主题的更多详细信息。 This thread on the Restlet-discuss list和this thread on the Linux kernel list也可能会引起人们的兴趣。
对于第二部分(未检测到写入此套接字的时间),这可能是缓冲区和超时的问题(正如其他人已经建议的那样)。
答案 4 :(得分:0)
我面临同样的问题。 我认为当您使用选择器注册套接字时,它不会抛出任何异常。 您是否在插座上使用选择器?