2014-02-07 2 views
0

우리는 클라이언트가 특정 시간 후에 연결이 끊기는 문제가 있습니다. 클라이언트 측의 예외는 "Read Timed out"메시지를 보여줍니다. 우리는 자바 애플리케이션에서 소켓 타임 아웃을 사용하지 않기 때문에 (기본값 0을 사용한다), 클라이언트의 타임 아웃은 프록시 또는 라우터 쪽에서 이루어져야한다. IT 부서에서이 문제를 조사하고 있습니다.소켓의 입력 스트림에서 닫기가 너무 오래 걸린다

그러나 연결이 중단되면 클라이언트 응용 프로그램이 소켓을 닫은 다음 서버에 대한 새 연결을 설정합니다. 동일한 클라이언트에서 새 연결을 수신하면 서버는 새 연결을 사용하기 전에 이전 연결에 대한 정리 작업을 시작합니다. 이러한 정리 작업은 서버가 EOS 또는 기타 읽기 예외를 감지하거나 동일한 클라이언트에서 새 연결을 수락하고 어떤 이유로 든 이전 연결이 정리되지 않은 경우에 발생합니다 (이는 서버 오류로 인해 발생합니다 EOS를 검출한다). 정리 작업에는 실제로 여러 로깅, 다양한 라우팅 데이터 구조 지우기 및 입력 및 출력 스트림의 마지막 닫기가 포함됩니다. 이 시점에서 우리는 이전 소켓 블록의 입력 스트림이 15 분 동안 닫히고 시간이 항상 동일하다는 사실을 관찰했습니다. 이해할 수 있듯이, 새로운 연결이 굶기 시작하고 같은 문제가 처음부터 반복적으로 시작되기 때문에 모든 것이 잘못되었습니다.

이제 우리 서버 측의 소켓이 FIN_WAIT_2 또는 TIME_WAIT 상태가 불명확하다고 가정합니다.이 상태에서 소켓은 필요한 ACK를받지 못한 상태로 남아 있습니다 (아마도 누락되었습니다). 그것은 CLOSED 상태에있다. 우리 서버가 처음에는 연결을 끊을 수있는 서버가 아니었지만 고객 측의 프록시 또는 라우터라고 가정합니다.이 프록시 또는 라우터가 시작되어 서버가 닫힌 것처럼 보였을 것입니다. 나는 그 상황을 도울 수있는 서버 측의 SO_LINGER 옵션을 0으로 설정하는 것을 읽었지만 (일반적으로 권장되지는 않지만). 참고 : 우리는 SO_LINGER 옵션으로 지금까지 혼란스러워하지는 않았지만 문제로 인해 그렇게 할 생각입니다.

그 이론이 사실인지 설명해 주시겠습니까? 게다가, 왜 소켓 클로즈 작업을 15 분 정도 걸립니까? 이것은 정상적인 2 * MSL (최대 세그먼트 수명) 기간을 초과합니다. 소켓 지속 시간을 기다리는 시간입니다. 우리는 아마도 SO_LINGER 옵션 (자바의 setSoLinger 메소드)의 값을 0보다 큰 값으로 설정해야할까요? 어떤 경우이든, 클라이언트는 이미 다른 쪽에서 연결을 중단 했으므로 소켓을 닫기 직전에 linger 옵션을 0으로 설정해도 클라이언트 측에서 다른 예외 나 잘못된 상태가 발생하지 않습니다. 게다가, 당신은 우리의 환경에서 떨어지는 패킷을 시뮬레이션 할 수있는 도구가 있습니까?

소켓 만들기 및 정리를 수행하는 코드는 특별한 것이 아닙니다.

Socket socket = new Socket(ipAddress, port); 
OutputStream dataOutputStream = new BufferedOutputStream(socket.getOutputStream(), 64000); 
InputStream dataInputStream = new BufferedInputStream(socket.getInputStream(), 64000); 

스트림 폐쇄 코드 소켓의 입력 스트림 소켓 및 출력 스트림을 닫으면

try { 
     if (dataInputStream != null) { 
      LOGGER.info("Going to close input stream...."); 
      dataInputStream.close(); 
     } 
    } finally { 
     if (dataOutputStream != null) { 
      LOGGER.info(".closeReaderWriter()", "Going to close output stream..."); 
      dataOutputStream.close(); 
     } 
    } 
+0

소켓을 인스턴스화하고, 소켓을 닫은 위치에서 코드를 다시 공유 할 수 있습니까? – Rainbolt

답변

0

그것을 플러싱없이 : 여기 단편이다. 이것의 유일한 실제 작업은 소켓을 닫는 것입니다. SO_LINGER 옵션을 사용하지 않는 한 소켓 닫기는 비동기식이므로 일반적으로 설명하는 상황은 발생할 수 없습니다.

결론 : 당신은 SO_LINGER 옵션으로 주위를 어지럽 혔습니다.

해결책 : 수행하지 마십시오.

다시 연결할 때까지 서버가 클라이언트 문제점을 감지 할 수 없다고합니다.

결론 : 이러한 읽기 시간 초과가 발생하면 클라이언트 응용 프로그램에서 소켓을 닫지 않습니다.

해결책 : 닫으십시오. 그런 다음 서버는 EOS를 읽고 소켓을 닫은 다음 기쁜 방법으로 계속 진행합니다.

소켓의 입력 스트림을 닫을 필요가 없습니다. 가장 바깥 쪽 출력 스트림/라이터를 닫아 소켓 출력 스트림을 감싸서 플러시되도록하고, 아마 finally 블록에있는 소켓 자체를 닫으십시오.

나머지 부분은 답변보다 많은 질문을 제기합니다.

  1. Java 응용 프로그램에서 어떻게 소켓 시간 초과를 완전히 비활성화 했습니까?
  2. 서버가 '정리 중'이라고 말하면서도 '처음부터 닫기를 시작하지 않았습니다'라고 말합니다. 왜 안돼?
+0

안녕 EJP. 우선 답에 감사드립니다. 나는 처음에는 분명하지 않았을지도 모른다. 귀하의 질문에 대한 답변은 편집 된 질문을보십시오. – ggkekas

+0

안녕 EJP. 우리의 클라이언트 응용 프로그램은 소켓에서 close를 수행하지만 EOS를 감지하기 위해 서버가 실패합니다. 그리고 이것은 우리의 가정이 고객의 프록시에 대한 이상한 반응을 기반으로하는 곳입니다. 프록시가 FIN 또는 RST 패키지를 보내면 우리 서버는 그 상황을 감지 할 수 없습니다. 또한 닫기가 비동기 작업이라고 생각하지 않습니다. close는 또한 클라이언트 측으로부터의 ACK를 기다려야 만한다. 이러한 ACK가 삭제되면 닫기가 오래 걸립니다. Java의 소스 코드는 가능한 긴 작업에 대한 경고를 표시합니다. – ggkekas

+0

DataInputStream.close()에 15 분이 걸리는 것으로 보입니다. 그렇지 않습니다. 그래서 무엇을합니까? 귀하의 질문은 명확하지 않습니다. – EJP

관련 문제