如何修复java.net.SocketException:管道坏了?

144 java sockets post exception

我正在使用apache commons http客户端使用post方法调用url来发布参数,并且它很少抛出以下错误.

java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
        at java.io.BufferedOutputStream.write(BufferedOutputStream.java:105)
        at java.io.FilterOutputStream.write(FilterOutputStream.java:80)
        at org.apache.commons.httpclient.methods.ByteArrayRequestEntity.writeRequest(ByteArrayRequestEntity.java:90)
        at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499)
        at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
        at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
Run Code Online (Sandbox Code Playgroud)

有人可以建议导致此异常的原因以及如何调试它吗?

use*_*421 76

这是因为当另一端已经关闭连接时写入连接.

因此,您的应用程序协议定义不明确或已实现.

  • 如果服务器端HTTP应用程序正在获取Broken Pipe异常,则仅表示客户端浏览器已退出/转到另一个页面/已超时/在历史记录中返回/无论如何.忘掉它. (25认同)
  • 你能帮我识别并纠正它吗?基本上,如何确认原因并修复? (4认同)
  • 我*确认了原因.你正在写,而另一端已经关闭了连接.修复不是这样做的.由于另一端没有阅读它,无论如何都没有任何意义.正如我所说,如果发生这种情况,您的应用程序协议规范或实现会出现问题,很可能您甚至没有. (4认同)
  • 我们在浏览器中中止ajax请求时看到了这个异常(使用`XMLHttpRequest.abort()`). (3认同)
  • 一个可能的原因是代理或Http服务器过早关闭连接.例如,J2EE服务器和应用程序客户机之间的Apache Http服务器,具有较短的定义超时.至少那是我们的生产环境发生的事情.客户抱怨页面没有完全加载我们在JBoss日志上看到了这个错误.经过一些测试后,我们注意到问题是配置不当的Http Server. (2认同)
  • 这是一个糟糕的答案,因为 OP 要求同时提供“原因”和“如何调试”......无论如何,导致它不一定(并且可以说很少)与“定义或实施不当的应用程序协议”相关。如前所述,这是因为套接字的侦听(服务器)端不会“通知”客户端连接已关闭,并且(例如在防火墙的情况下)甚至可能不知道从客户端的角度来看它已关闭。至于调试,知道它关闭的方法是尝试写入,至于原因,必须通过网络套接字链(代理等)追踪到服务器。 (2认同)

小智 30

在我们的案例中,我们在应用服务器上执行负载测试时遇到了这种情况.问题是我们需要为JVM添加额外的内存,因为它已经用完了.这解决了这个问题.

尝试增加JVM可用的内存,或者在出现这些错误时监视内存使用情况.

  • 我在负载测试期间遇到了同样的问题.我想数据需要花费很多时间才能生成,负载测试工具不会等待足够长的数据然后关闭连接.我的情况是,添加内存可能会缩短数据生成过程的持续时间,因此负载测试可以获得没有超时限制的所有数据.增加内存的另一种方法是增加负载测试工具的超时时间. (3认同)
  • 显然,低内存导致应用程序关闭接收套接字或实际上完全退出,具有相同的效果。低内存*本身*不会导致管道损坏。 (2认同)
  • 这实际上在我们的重负载应用程序中似乎也是一个问题 (2认同)

And*_*Gee 7

SocketException:管道损坏,是由代码读取或写入连接时关闭连接的"另一端"(客户端或服务器)引起的.

这是客户端/服务器应用程序中非常常见的例外,它从应用程序控件之外的客户端或服务器接收流量.例如,客户端是浏览器.如果浏览器进行Ajax调用,和/或用户只是关闭页面或浏览器,那么这可以有效地意外地终止所有通信.基本上,只要另一端终止其应用程序,您就会看到此错误,并且您没有预料到它.

如果您在应用程序中遇到此异常,那么这意味着您应检查发生IO(输入/输出)的代码,并使用try/catch块将其包装以捕获此IOException.然后,由您决定如何处理这种半有效的情况.

在你的情况,最早的地方,你还是得控制是调用HttpMethodDirector.executeWithRetry-所以确保调用包装用try/catch块,并处理它,你怎么认为合适的.

我强烈建议不要在调试/跟踪级别以外的任何地方记录SocketException-Broken Pipe特定错误.否则,这可以通过填充日志作为DOS(拒绝服务)攻击的一种形式.针对这种常见情况,尝试并强化并对您的应用程序进行负面测试.


小智 5

所有打开的流和连接都需要正确关闭,所以下次我们尝试使用 urlConnection 对象时,它不会抛出错误。例如,以下代码更改为我修复了错误。

前:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();
Run Code Online (Sandbox Code Playgroud)

后:

OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();
os.close(); // This is a must.
Run Code Online (Sandbox Code Playgroud)

  • 这实际上很奇怪,因为`BufferedOutputStream` 总是在其底层输出流上调用`close()`(因此在`urlConnection` 的输出流上)。请参阅 http://docs.oracle.com/javase/6/docs/api/java/io/BufferedOutputStream.html 和 http://docs.oracle.com/javase/6/docs/api/java/io/FilterOutputStream .html#close() 所以当你调用 `os.close()` 时,它应该已经关闭了。不? (8认同)
  • “os.close()”不是“必须的”。'out.close()' 也不是。'bw.close()' 就足够了。@obedker 是正确的。仅此更改无法解决问题。 (4认同)