java.net.SocketException: 软件原因引起的连接中断: 接收失败

96

我找不到一个合适的答案来解释下面这个错误具体意味着什么:

java.net.SocketException: Software caused connection abort: recv failed

备注:

  • 这个错误不经常出现,而且是不可预测的;虽然出现这个错误会导致所有未来对于URI的请求也将失败。
  • 唯一有效的解决方案(也只是偶尔有效)是重新启动Tomcat和/或实际的机器(在这种情况下是Windows)。
  • URI绝对可用(通过询问浏览器进行抓取得到的确认)。

相关代码:

BufferedReader reader;
try { 
 URL url = new URL(URI);
 reader = new BufferedReader(new InputStreamReader(url.openStream())));
} catch( MalformedURLException e ) { 
 throw new IOException("Expecting a well-formed URL: " + e); 
}//end try: Have a stream

String buffer;
StringBuilder result = new StringBuilder();
while( null != (buffer = reader.readLine()) ) { 
 result.append(buffer); 
}//end while: Got the contents.
reader.close();

4
嗨,你标记了答案为正确的 - 你能否记得你通过嗅探找到了什么? 这个问题困扰着我。(请参见我的问题https://dev59.com/h1nUa4cB1Zd3GeqPaXTy) - nasty pasty
10个回答

36

如果您的TLS客户端无法通过需要客户端身份验证的服务器进行身份验证,则也会发生这种情况。


不,它不会。这会导致服务器使用TLS的close_notify正确关闭连接。没有任何重置,或者最多是“对等方重置连接”。 - user207421
3
有些API在身份验证失败时会出现这种情况,我也遇到过。所以感谢@desbocages。 - Eddy
这是我Apache设置出错的原因。 - Atuos
当连接到需要相互认证的Apache Tomcat 7.0.42服务器时,我在尝试使用一张证书进行身份验证时收到了这个确切的错误,因为该证书的信任链不在Tomcat在SSL握手期间提供的受信任证书列表中。顺便说一下,我用于身份验证的证书在信任列表中,但其信任链不在其中,仍然出现了此错误。 - Daniel
1
我在客户端收到了"java.net.SocketException: Software caused connection abort: recv failed"错误信息,并检查了服务器端(Apache HTTPD)的日志文件,发现了"Certificate Verification: Error (10): certificate has expired"的错误信息。双向认证已经配置,但我的客户端证书已经过期。很遗憾,客户端无法获得更详细的错误信息。 - Ryan

33

这通常意味着存在网络错误,例如TCP超时。建议首先放置一个嗅探器(wireshark)对连接进行监测,以查看是否存在问题。 如果存在TCP错误,则应该能够看到它。此外,如果适用,您可以检查路由器日志。如果涉及无线电波,则另一个可能出现此类错误的来源。


15

这个错误是在连接突然关闭时发生的(当TCP连接在发送缓冲区中仍有数据时被重置)。这种情况与更常见的“对等方重置连接”非常相似。它可能会在通过互联网连接时偶尔发生,但如果时间合适(例如,在本地主机上使用保持活动连接),则也可能成为系统问题。

HTTP客户端应该只需重新打开连接并重试请求即可。重要的是要理解,在此状态下,除了关闭连接外,没有其他方法可以解决它。任何尝试发送或接收数据都将产生相同的错误。

不要使用URL.open(),而是使用Apache-Commons HttpClient,它具有重试机制、连接池、保持活动连接和许多其他功能。

用法示例:

HttpClient httpClient = HttpClients.custom()
            .setConnectionTimeToLive(20, TimeUnit.SECONDS)
            .setMaxConnTotal(400).setMaxConnPerRoute(400)
            .setDefaultRequestConfig(RequestConfig.custom()
                    .setSocketTimeout(30000).setConnectTimeout(5000).build())
            .setRetryHandler(new DefaultHttpRequestRetryHandler(5, true))
            .build();
// the httpClient should be re-used because it is pooled and thread-safe.

HttpGet request = new HttpGet(uri);
HttpResponse response = httpClient.execute(request);
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
// handle response ...

4
你是否正在访问http数据?你可以使用HttpClient库代替标准库吗?该库具有更多选项,并提供更好的错误信息。 http://hc.apache.org/httpclient-3.x/

4
我曾经遇到类似的情况,通常是由于网络连接不佳或者其他线程关闭了我正在使用的套接字导致的。

2
尝试在jdbc连接字符串中添加'autoReconnect=true'。

1

这种情况有时会发生,无论是因为连接超时还是远程主机终止了它们的连接(关闭应用程序、计算机关机等)。您可以通过自己管理套接字并通过其通信协议处理断开连接,然后调用shutdownInputshutdownOutput来清除会话,从而避免这种情况的发生。


1

请检查是否有其他服务或程序在HTTP端口上运行。当我尝试使用该端口时,就发生了这种情况,因为它被另一个程序占用了。


0
如果您正在使用Netbeans管理Tomcat,请尝试在“工具-服务器”中禁用HTTP监视器。

0

我也曾遇到过这个问题。我的解决方案是:

sc.setSoLinger(true, 10);

从网站复制 -->通过使用setSoLinger()方法,您可以明确设置延迟时间,然后发送重置信号,为数据读取或发送提供更多时间。

也许这不是每个人的答案,但对某些人来说是有用的。


3
这是不正确的。SO_LINGER并没有做任何这样的事情。它控制close()阻塞的时间长短,如果有的话。它与复位的时间无关。而“从网站复制”不是一个恰当的引用形式。您应该提供链接,以便我们可以看到它真正的含义,并在必要时进行负面评论。我知道你从哪里找来的,这从头到尾都是一堆废话。我在15年前给他寄了很多更正意见:他发了脾气,之后就再也没更新过了。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接