如何修复java.net.socketexception:损坏的管道?

tvmytwxo  于 2021-07-08  发布在  Java
关注(0)|答案(10)|浏览(373)

我使用ApacheCommonsHTTP客户机调用url,使用post方法发布参数,它很少抛出以下错误。

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)

有人能建议是什么导致了这个异常以及如何调试它吗?

ufj5ltwl

ufj5ltwl1#

原因是远程对等端关闭了它的套接字(例如崩溃),因此如果您尝试向它写入数据,您将得到这个结果。要解决这个问题,请保护之间的读/写套接字操作(try catch),然后将丢失连接的情况管理到catch中(续订连接、停止程序等):

try {
      /* your code */
 } catch (SocketException e) {
      e.printStackTrace();
      /* insert your failure processings here */
 }
c9x0cxw0

c9x0cxw02#

javadoc公司:
传入连接指示(连接请求)的最大队列长度设置为50。如果连接指示在队列已满时到达,则连接将被拒绝。
例如,您应该增加serversocket的“backlog”参数

int backlogSize = 50 ;
new ServerSocket(port, backlogSize);
noj0wjuj

noj0wjuj3#

在本例中,我们在应用服务器上执行负载测试时遇到了这种情况。问题是我们需要向jvm添加额外的内存,因为它已经用完了。这就解决了问题。
尝试增加jvm可用的内存,或者在出现这些错误时监视内存使用情况。

j0pj023g

j0pj023g4#

这是由于:
最常见的情况是,在另一端已经关闭连接时写入连接;
通常情况下,对等端会关闭连接而不读取其端已挂起的所有数据。
因此,在这两种情况下,您都有一个定义或实现得不好的应用程序协议。
还有第三个原因,我将不在这里记录,但涉及到同行采取蓄意行动重置,而不是适当地关闭连接。

xyhw6mcr

xyhw6mcr5#

问题可能是您部署的文件没有使用正确的rmi方法进行更新。检查rmi接口是否更新了参数,或者更新了客户端没有的数据结构。或者您的rmi客户机没有与服务器版本不同的参数。
这只是一个有根据的猜测。在重新部署服务器应用程序的类文件并重新测试之后,“管道断裂”的问题消失了。

isr3a4wc

isr3a4wc6#

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

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();

之后:

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.
xyhw6mcr

xyhw6mcr7#

以上答案说明了原因 java.net.SocketException: Broken pipe :另一端关闭了连接。我想分享一下我遇到它时的经历:
在客户的请求中 Content-Type 标头被错误地设置为大于请求主体的实际大小(实际上根本没有主体)
tomcatsocket中的底层服务正在等待那个大小的主体数据(http在tcp上,它通过封装和…)来确保交付)
当60秒过期时,tomcat抛出超时异常: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception java.net.SocketTimeoutException: null 由于超时异常,客户端收到状态代码为500的响应。
客户端关闭连接(因为它接收响应)。
tomcat抛出 java.net.SocketException: Broken pipe 因为客户把它关了。
有时,tomcat不会抛出中断的pip异常,因为超时异常关闭了连接,为什么这样的差异让我也很困惑。

8i9zcol2

8i9zcol28#

我已经通过ftp服务器实现了数据下载功能,在恢复下载时也发现了同样的异常。要解决此异常,必须始终断开与上一个会话的连接,并创建新的客户端示例和与服务器的新连接。同样的方法也可能对httpclient有所帮助。

8wtpewkr

8wtpewkr9#

socketexception:管道断裂,是由于“另一端”(客户端或服务器)在代码读取或写入连接时关闭连接造成的。
在从应用程序控制之外的客户端或服务器接收通信的客户端/服务器应用程序中,这是一个非常常见的异常。例如,客户端是一个浏览器。如果浏览器发出ajax调用,和/或用户简单地关闭页面或浏览器,那么这将有效地意外终止所有通信。基本上,当另一端终止应用程序时,您会看到这个错误,而您并没有预料到。
如果在应用程序中遇到此异常,则意味着您应该检查发生io(输入/输出)的代码,并用try/catch块将其 Package 以捕获此ioexception。然后,由你决定如何处理这种半有效的情况。
在您的情况下,最早您仍有控制权的地方是调用 HttpMethodDirector.executeWithRetry -因此,请确保使用try/catch块 Package 调用,并以您认为合适的方式处理它。
我强烈建议不要在调试/跟踪级别之外的任何地方记录socketexception中断管道特定错误。否则,可以通过填充日志将其用作dos(拒绝服务)攻击的一种形式。针对这种常见情况,尝试对应用程序进行强化和负面测试。

t9eec4r0

t9eec4r010#

我在开发一个简单的java应用程序时遇到了同样的问题,该应用程序监听特定的tcp。通常,我没有问题,但当我运行一些压力测试时,我注意到一些连接因错误而中断 socket write exception .
经过调查,我找到了解决问题的办法。我知道这个问题已经很老了,但我更愿意和大家分享我的解决方案,有人会发现它很有用。
问题出在serversocket创建上。我从javadoc中了解到,默认限制为50个挂起的套接字。如果您尝试打开另一个连接,这些连接将被拒绝。解决方案只是在服务器端更改这个默认配置。在下面的例子中,我创建了一个在tcp端口侦听的socket服务器 10_000 接受max 200 挂起的套接字。

new Thread(() -> {
      try (ServerSocket serverSocket = new ServerSocket(10_000, 200)) {
        logger.info("Server starts listening on TCP port {}", port);

        while (true) {
          try {
            ClientHandler clientHandler = clientHandlerProvider.getObject(serverSocket.accept(), this);
            executor.execute(clientHandler::start);
          } catch (Exception e) {
            logger.error(e.getMessage());
          }
        }

      } catch (IOException | SecurityException | IllegalArgumentException e) {
        logger.error("Could not open server on TCP port {}. Reason: {}", port, e.getMessage());
      }
    }).start();

从serversocket的javadoc:
传入连接指示(连接请求)的最大队列长度设置为backlog参数。如果连接指示在队列已满时到达,则连接将被拒绝。

相关问题