Как исправить java.net.SocketException: Неработающая труба?

Я использую HTTP-клиент apache commons для вызова 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)

Может кто-нибудь предположить, что вызывает это исключение и как его отлаживать?

Ответ 1

Это вызвано:

  • чаще всего, запись в соединение, когда другой конец уже закрыл его;
  • реже, одноранговый узел закрывает соединение, не считывая все данные, которые уже ожидают в его конце.

Таким образом, в обоих случаях у вас есть плохо определенный или реализованный протокол приложения.

Есть третья причина, которую я не буду здесь документировать, но которая заключается в том, что одноранговый узел предпринимает преднамеренные действия для сброса, а не для правильного закрытия соединения.

Ответ 2

В нашем случае мы испытали это при выполнении нагрузочного теста на нашем сервере приложений. Выяснилось, что нам нужно добавить дополнительную память в нашу JVM, потому что она заканчивается. Это решило проблему.

Попробуйте увеличить доступную память к JVM и/или контролировать использование памяти при получении этих ошибок.

Ответ 3

SocketException: Сломанная трубка вызвана "другим концом" (клиентом или сервером), закрывающим соединение, когда ваш код либо читает, либо записывает в соединение.

Это очень распространенное исключение в клиент-серверных приложениях, которые получают трафик от клиентов или серверов за пределами управления приложениями. Например, клиент является браузером. Если браузер делает вызов Ajax, и/или пользователь просто закрывает страницу или браузер, то это может эффективно убить всю коммуникацию неожиданно. В принципе, вы увидите эту ошибку в любое время, когда другой конец прекратит свое приложение, и вы не ожидали этого.

Если вы испытываете это исключение в своем приложении, это означает, что вы должны проверить свой код, где находится IO (ввод/вывод), и обернуть его блоком try/catch, чтобы поймать это исключение IOException. Тогда вам решать, как вы хотите справиться с этой полуправдой.

В вашем случае самым ранним местом, где у вас все еще есть контроль, является вызов HttpMethodDirector.executeWithRetry. Поэтому убедитесь, что вызов завершен блоком try/catch и обрабатывает его, как вы считаете нужным.

Я бы настоятельно советовал не регистрировать ошибки SocketException-Broken Pipe на любых других уровнях, кроме уровней отладки/трассировки. Кроме того, это может быть использовано как форма атаки DOS (Denial Of Service) путем заполнения журналов. Попробуйте и затвердите и отрицательно проверьте приложение на этот общий сценарий.

Ответ 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.

Ответ 5

Я реализовал функцию загрузки данных через FTP-сервер и обнаружил там одно и то же исключение при возобновлении этой загрузки. Чтобы устранить это исключение, вам всегда придется отключиться от предыдущего сеанса и создать новый экземпляр клиента и новое соединение с сервером. Этот же подход может быть полезен и для HTTPClient.

Ответ 6

Проблема может заключаться в том, что ваши развернутые файлы не обновляются с помощью правильных методов RMI. Убедитесь, что в вашем интерфейсе RMI обновлены параметры или обновлены структуры данных, которых нет у вашего клиента. Или что ваш клиент RMI не имеет параметров, которые отличаются от версии вашего сервера.

Это всего лишь образованная догадка. После повторного развертывания моих файлов классов приложений и повторного тестирования проблема "Broken pipe" исчезла.

Ответ 7

Причина в том, что удаленный узел закрывает свой сокет (например, сбой), поэтому, если вы попытаетесь записать данные для него, например, вы получите это. Чтобы решить эту проблему, защитите операции чтения/записи в сокет между (попытайтесь перехватить), затем перенесите случай потери соединения в перехват (обновить соединение, остановить программу и т.д.):

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

Ответ 8

Приведенные ответы иллюстрируют причину этого java.net.SocketException: Broken pipe: другой конец закрыл соединение. Я хотел бы поделиться опытом, что случилось, когда я столкнулся с ним:

  • в запросе клиента заголовок Content-Type ошибочно установлен больше, чем тело запроса фактически (на самом деле вообще не было тела)
  • нижняя служба в tomcat-соке ожидала данных размера тела (http на TCP, который обеспечивает доставку путем инкапсуляции и...)
  • когда истекает 60 секунд, исключение тайм-аута tomcat: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception java.net.SocketTimeoutException: null
  • клиент получает ответ с кодом состояния 500 из-за исключения тайм-аута.
  • закрыть клиентское соединение (поскольку он получает ответ).
  • tomcat throws java.net.SocketException: Broken pipe, потому что клиент закрыл его.

Иногда, tomcat не бросает исключение исключенной схемы, потому что исключение тайм-аута закрывает соединение, почему такое различие меня тоже пугает.

Ответ 9

В моем случае это произошло потому, что версия не была динамической переменной в pom.xml.

Версия в pom.xml была "1.0.SNAPSHOT"
Я изменил это на

$ {Вер}

Первая сборка пройдена, но следующая сборка пытается развернуться в том же месте, для которого соединение уже закрыто.

После смены версии это было решено для меня.

Ответ 10

JavaDoc:

Максимальная длина очереди для входящих указаний подключения (a запрос на подключение) устанавливается на 50. Если появляется индикация соединения когда очередь заполнена, соединение будет отклонено.

Вы должны увеличить параметр "backlog" вашего ServerSocket, например

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