繁体   English   中英

Java套接字没有在死套接字上抛出异常?

[英]Java socket not throwing exceptions on a dead socket?

我们的移动设备和服务器之间都有一个简单的客户端服务器架构,都是用Java编写的。 一个非常简单的ServerSocket和Socket实现。 然而,一个问题是当客户端突然终止(没有正确关闭套接字)时,服务器不知道它已断开连接。 此外,服务器可以继续写入此套接字而不会出现任何异常。 为什么?

根据文档,如果您尝试写入另一端无法访问的套接字,Java套接字应该抛出异常!

最终将通过Retransmit Timeout(RTO)超时连接。 但是,RTO是使用基于网络延迟(RTT)的复杂算法计算的,请参阅此RFC,

http://www.ietf.org/rfc/rfc2988.txt

所以在移动网络上,这可能是几分钟。 等待10分钟,看看是否可以暂停。

这类问题的解决方案是在您自己的应用程序协议中添加一个心跳,并在您未获得心跳确认时断开连接。

这里的关键词(without closing the socket properly)

应始终以这种方式获取和处理套接字:

final Socket socket = ...; // connect code

try
{
    use( socket ); // use socket
}
finally
{
    socket.close( ); // dispose
}

即使采取这些预防措施,您也应该指定特定于您的协议的应用程序超时。

我的经验表明,遗憾的是,您无法可靠地使用任何Socket超时功能(例如,写操作没有超时,甚至读操作有时可能永远挂起)。

这就是为什么你需要一个看门狗线程来强制你的应用程序超时并处理一段时间没有响应的套接字。

一种方便的方法是通过java.nio中的相应通道初始化Socket和ServerSocket。 这种套接字的主要优点是它们是可中断的,这样你就可以简单地中断执行套接字协议的线程,并确保套接字正确处理掉。

请注意,您应该在双方强制执行应用程序超时,因为当您遇到无响应的套接字时,这只是时间问题和运气不好。

TCP / IP通信可能非常奇怪。 TCP将在堆栈的底层重试相当长一段时间,而不会让上层知道发生了什么。

我完全可以期待在一段时间(30秒到几分钟)之后你会看到一个错误,但我还没有测试过这个我只是关闭TCP应用程序的工作方式。

您可能能够收紧TCP规范(重试,超时等),但再次,没有太多搞乱它。

此外,它可能是我完全错了,你正在使用的Java的实现是不稳定的。

要回答问题的第一部分(关于不知道客户端突然断开连接),在TCP中,在尝试使用连接之前,您无法知道连接是否已经结束。

TCP保证交付的概念非常微妙:实际上并不保证交付给另一端的应用程序(它取决于真正的保证方式)。 RFC 793(TCP)的2.6节提供了有关此主题的更多详细信息。 Restlet讨论列表中的 这个线程以及Linux内核列表中的这个线程也可能是有意义的。

对于第二部分(不检测何时写入此套接字),这可能是缓冲区和超时的问题(正如其他人已经建议的那样)。

我面临同样的问题。 我认为当您使用选择器注册套接字时,它不会抛出任何异常。 你在插座上使用选择器吗?

暂无
暂无

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

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