[java] java.net.SocketException 수정하는 방법 : 깨진 파이프?

매개 변수를 게시하기 위해 post 메소드를 사용하여 URL을 호출하기 위해 Apache Commons http 클라이언트를 사용하고 있으며 아래 오류가 거의 발생하지 않습니다.

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)

누군가이 예외의 원인과 디버깅 방법을 제안 할 수 있습니까?



답변

이 원인은 다음과 같습니다.

  • 가장 일반적으로, 다른 쪽 끝이 이미 닫 혔을 때 연결에 쓰는 것;
  • 덜 일반적으로, 피어는 끝에서 이미 보류중인 모든 데이터를 읽지 않고 연결을 닫습니다.

따라서 두 경우 모두 응용 프로그램 프로토콜이 잘못 정의되었거나 구현되었습니다.

여기에 문서화하지는 않지만 연결을 올바르게 닫지 않고 재설정하기 위해 의도적으로 조치를 취하는 피어와 관련된 세 번째 이유가 있습니다.


답변

우리의 경우 앱 서버에서로드 테스트를 수행하는 동안이 문제가 발생했습니다. 이 문제는 JVM에 메모리가 부족하여 추가 메모리를 추가해야한다는 것이 밝혀졌습니다. 문제가 해결되었습니다.

JVM에 사용 가능한 메모리를 늘리거나 해당 오류가 발생하면 메모리 사용량을 모니터하십시오.


답변

SocketException : 끊어진 파이프는 코드에서 연결을 읽거나 쓰는 동안 ‘다른 쪽'(클라이언트 또는 서버)이 연결을 닫아서 발생합니다.

응용 프로그램 제어 외부의 클라이언트 또는 서버에서 트래픽을 수신하는 클라이언트 / 서버 응용 프로그램에서는 매우 일반적인 예외입니다. 예를 들어 클라이언트는 브라우저입니다. 브라우저가 Ajax 호출을하거나 사용자가 단순히 페이지 나 브라우저를 닫으면 모든 통신이 예기치 않게 중단 될 수 있습니다. 기본적으로, 다른 쪽 끝이 응용 프로그램을 종료 할 때마다이 오류가 표시되며 예상하지 않았습니다.

애플리케이션에서이 예외가 발생하면 IO (입력 / 출력)가 발생하는 코드를 확인하고 try / catch 블록으로 랩하여이 IOException을 포착해야 함을 의미합니다. 이 반 유효한 상황을 어떻게 처리할지 결정하는 것은 사용자의 책임입니다.

귀하의 경우, 귀하가 여전히 통제 할 수있는 가장 빠른 장소는 HttpMethodDirector.executeWithRetry 따라서 try / catch 블록으로 전화를 감싸고 귀하가 적합한 방식으로 처리하도록하십시오.

디버그 / 추적 레벨 이외의 다른 곳에서 SocketException-Broken Pipe 특정 오류를 기록하지 않도록 강력히 권장합니다. 그렇지 않으면 로그를 채워서 DOS (서비스 거부) 공격의 형태로 사용할 수 있습니다. 이 일반적인 시나리오에 대해 애플리케이션을 시험해보고 강화하십시오.


답변

열려있는 모든 스트림과 연결을 올바르게 닫아야하므로 다음에 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.


답변

FTP 서버를 통해 데이터 다운로드 기능을 구현했으며 해당 다운로드를 다시 시작하는 동안 동일한 예외가 발견되었습니다. 이 예외를 해결하려면 항상 이전 세션에서 연결을 끊고 클라이언트의 새 인스턴스와 서버와의 새 연결을 작성해야합니다. 이와 동일한 접근 방식이 HTTPClient에도 도움이 될 수 있습니다.


답변

특정 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에서 :

들어오는 연결 표시 (연결 요청)의 최대 큐 길이는 백 로그 매개 변수로 설정됩니다. 큐가 가득 찼을 때 연결 표시가 도착하면 연결이 거부됩니다.


답변

배포 된 파일이 올바른 RMI 방법으로 업데이트되지 않았을 수 있습니다. RMI 인터페이스에 업데이트 된 매개 변수 또는 클라이언트에없는 데이터 구조가 업데이트되었는지 확인하십시오. 또는 RMI 클라이언트에 서버 버전과 다른 매개 변수가 없습니다.

이것은 단지 교육받은 추측 일뿐입니다. 서버 응용 프로그램의 클래스 파일을 다시 배포하고 다시 테스트 한 후 “깨진 파이프”문제가 사라졌습니다.