java.net.SocketException:连接重置
我在尝试从套接字读取时遇到以下错误。我在那个InputStream上做一个readInt(),并且遇到这个错误。仔细阅读文档,这表明连接的客户端部分关闭了连接。在这种情况下,我是服务器。
我可以访问客户端日志文件,但它没有关闭连接,实际上,它的日志文件表明我正在关闭连接。那么,有人知道为什么会这样吗?还有什么要检查的?当本地资源可能达到阈值时,会发生这种情况吗?
我确实注意到我有以下几行:
socket.setSoTimeout(10000);
就在readInt()
之前。这是有原因的(长话短说),但出于好奇,在某些情况下会导致所指示的错误吗?我在IDE中运行服务器,但碰巧我的IDE停留在断点上,然后我发现完全相同的错误开始出现在我自己的IDE中。
无论如何,仅提及它,希望它不会成为红色鲱鱼。 :-(
解决方案
回答
每当遇到类似这样的奇怪问题时,我通常都会坐下来使用WireShark之类的工具,查看来回传递的原始数据。在断开连接的情况下,我们可能会感到惊讶,并且只有在尝试阅读时才会收到通知。
回答
连接重置仅表示已接收到TCP RST。当对等方收到无法处理的数据时,就会发生这种情况,并且可能有多种原因。
最简单的方法是关闭套接字,然后在输出流上写入更多数据。通过关闭套接字,我们告诉对等端我们已经完成通话,并且它可以忘记连接。无论如何,当我们在该流上发送更多数据时,对等方都会通过RST拒绝它,以让我们知道它不在监听。
在其他情况下,介入的防火墙甚至远程主机本身可能"忘记"TCP连接。如果我们长时间不发送任何数据(通常是2个小时),或者因为对等方已重新启动并丢失了有关活动连接的信息,则可能会发生这种情况。在这些无效连接之一上发送数据也会导致RST。
更新以响应其他信息:
请仔细查看我们对SocketTimeoutException
的处理。如果在套接字操作上被阻止时超过了配置的超时,则会引发此异常。抛出此异常时,套接字本身的状态不会更改,但是如果异常处理程序关闭了套接字,然后尝试对其进行写入,则我们将处于连接重置状态。 setSoTimeout()旨在为我们提供一种干净的方法来打破可能永久阻塞的read()操作,而无需执行诸如从另一个线程关闭套接字的肮脏操作。
回答
有几种可能的原因。
- 另一端故意重设了连接,在此我将不做记录。应用程序软件很少会这样做,而且通常是不正确的,但对于商业软件而言却并非未知。
- 更常见的是,由于写入连接导致另一端已经正常关闭。换句话说,应用程序协议错误。
- 当套接字接收缓冲区中有未读数据时,关闭套接字也会导致此错误。
- 在Windows中,"软件引起的连接中止"与"连接重置"不同,这是由我们端发送的网络问题引起的。有关于此的Microsoft知识库文章。