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

时间:2010-02-22 08:08:15

标签: java exception post sockets

我正在使用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)

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

10 个答案:

答案 0 :(得分:73)

这是由:

引起的
  • 最常见的是,当另一端已经关闭时写入连接;
  • 通常情况下,对等方关闭连接而不读取其末尾已经挂起的所有数据。

因此,在这两种情况下,您都有一个定义不明确或实施的应用程序协议。

还有第三个原因,我不会在这里记录,但是其中涉及对等方采取故意行动来重置而不是正确关闭连接。

答案 1 :(得分:28)

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

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

答案 2 :(得分:7)

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

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

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

在您的情况下,您仍然可以控制的最早的地方是对HttpMethodDirector.executeWithRetry的调用 - 因此请确保使用try / catch块包装调用,并按照您认为合适的方式处理它。

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

答案 3 :(得分:4)

所有开放流和&连接需要正确关闭,所以下次我们尝试使用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.

答案 4 :(得分:2)

在开发一个侦听特定TCP的简单Java应用程序时,我遇到了同样的问题。通常,我没有问题,但是当我进行一些压力测试时,我发现某些连接因错误socket write exception而中断。

调查后,我找到了解决我的问题的解决方案。我知道这个问题已经很久了,但是我更愿意分享我的解决方案,有人会发现它很有用。

问题出在ServerSocket创建上。我从Javadoc中读取,默认限制为50个待处理的套接字。如果您尝试打开另一个连接,这些将被拒绝。解决方案仅在于在服务器端更改此默认配置。在以下情况下,我创建了一个侦听TCP端口10_000并接受最多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参数。如果在队列已满时出现连接指示,则拒绝连接。

答案 5 :(得分:1)

我已经通过FTP服务器实现了数据下载功能,并且在恢复下载时也发现了相同的异常。 要解决此异常,您将始终必须断开与上一个会话的连接,并创建客户端的新实例以及与服务器的新连接。这种方法对HTTPClient也有帮助。

答案 6 :(得分:0)

问题可能是您使用正确的RMI方法更新了部署的文件。检查您的RMI接口是否已更新参数,或客户端没有的更新数据结构。或者您的RMI客户端没有与服务器版本不同的参数。

这只是一个有根据的猜测。在重新部署我的服务器应用程序的类文件并重新测试之后,“Broken pipe”的问题就消失了。

答案 7 :(得分:0)

以上答案说明了java.net.SocketException: Broken pipe的原因:另一端关闭了连接。我想分享一下遇到它时发生的事情:

  1. 在客户的请求中,Content-Type标题被错误地设置为大于请求正文实际上(事实上根本没有正文)
  2. tomcat套接字中的底层服务正在等待那个大小的正文数据(http在TCP上,它确保通过封装和...来传递)
  3. 当60秒过期时,tomcat抛出异常时间: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception java.net.SocketTimeoutException: null
  4. 客户端因超时异常而收到状态码为500的响应。
  5. 客户端关闭连接(因为它收到响应)。
  6. tomcat抛出java.net.SocketException: Broken pipe因为客户关闭了它。
  7. 有时候,tomcat不会抛出破坏的pip异常,因为超时异常关闭连接,为什么这样的差异也让我感到困惑。

答案 8 :(得分:0)

我注意到我在制作它时使用了不正确的 HTTP 请求 url,后来我改变了它解决了我的问题。我的上传网址是:http://192.168.0.31:5000/uploader,而我正在使用 http://192.168.0.31:5000。那是一个 get 电话。并得到一个 java.net.SocketException: Broken pipe?例外。

这就是我的理由。这个问题可能会让你多检查一点

  public void postRequest()  {


        Security.insertProviderAt(Conscrypt.newProvider(), 1);

        System.out.println("mediafilename-->>" + mediaFileName);
        String[] dirarray = mediaFileName.split("/");
        String file_name = dirarray[6];
        //Thread.sleep(10000);

        RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file",file_name, RequestBody.create(MediaType.parse("video/mp4"), new File(mediaFileName))).build();
        OkHttpClient okHttpClient = new OkHttpClient();
//        ExecutorService executor = newFixedThreadPool(20);
//        Request request = new Request.Builder().post(requestBody).url("https://192.168.0.31:5000/uploader").build();
        Request request = new Request.Builder().url("http://192.168.0.31:5000/uploader").post(requestBody).build();
//        Request request = new Request.Builder().url("http://192.168.0.31:5000").build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {

//

                call.cancel();

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(),"Something went wrong:" + " ", Toast.LENGTH_SHORT).show();

                    }
                });
                e.printStackTrace();

            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {


                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        try {
                            System.out.println(response.body().string());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });


                System.out.println("Response ; " + response.body().toString());
//                Toast.makeText(getApplicationContext(), response.body().toString(),Toast.LENGTH_LONG).show();
                System.out.println(response);

            }
        });

答案 9 :(得分:-1)

  

的JavaDoc:

     

传入连接指示的最大队列长度(a   请求连接)设置为50.如果连接指示到达   当队列已满时,连接被拒绝。

你应该增加"积压" ServerSocket的参数,例如

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