2009-03-24 4 views
3

조사가 진행되는 동안 누군가가 우리에게 도움이되기를 바랍니다.TCP 소켓 서버가 CLOSE_WAITs를 정상적으로 생성하지 못함 작동하지 않을 때까지

우리는 C#으로 작성된 간단한 비동기 소켓 서버를 ASP.NET 웹 응용 프로그램의 연결을 받아들이고 메시지를 보내고 일부 처리 (일반적으로 DB뿐만 아니라 다른 시스템에 대해서도)를 수행 한 다음 응답을 보냅니다 다시 클라이언트에게. 클라이언트가 연결 종료를 담당합니다.

우리는 시스템이 오랜 기간 동안 (보통 며칠간) 과부하 상태에있는 경우 프로세스가 수행 할 수없는 정도까지 서버 상자 (netstat -a)에 CLOSE_WAIT 소켓이 쌓이게되었습니다 더 이상의 연결을 수락하십시오. 그 시점에서 우리는 프로세스를 바운스하고 다시 실행합니다.

우리는 ASP.NET 응용 프로그램의 일부로드 테스트를 실행하여 문제를 복제하려고 시도했습니다. 코드의 일부 문제를 추론 할 수 없었기 때문에 문제를 재현하려고 시도했습니다.

은 System.Net.Sockets.SocketException : 기존의 연결이 강제로 폐쇄되었다 우리는 우리가 이것을 관리하고 소켓 서버의 로그에서의 SocketException으로 스스로를 만들어 낸 문제의 WireShark로 packet trace으로 돌아가 셨습니다 것 같아요 System.Net.Sockets.Socket.BeginSend (바이트 [] 버퍼 오프셋 INT32, INT32 크기 socketFlags socketFlags, AsyncCallback 콜백, 객체 상태)에서 원격 호스트는

난에서 문제를 재현 시도한 단일 ASP.NET 응용 프로그램과 동일한 코드를 사용하여 소켓 서버에 직접 연결하는 단일 스레드 프로세스로 패킷 추적을 수행 할 수 없습니다.

아무도 우리가 잘못했을 가능성이 있는지 확인하거나 시도 할 다음 일을 제안하지 않았습니까?

답변

5

봐는

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

당신의 클라이언트는 FIN 지금 CLOSE_WAIT로 변경의 상태 및 숙박을 애크 서버 소켓에 FIN을 보내 close()를 호출하여 연결을 폐쇄 서버가 소켓에 close() 호출을하지 않는 한 그런 식으로.

서버 프로그램은 클라이언트가 연결을 중단했는지 여부를 감지 한 다음 즉시 포트를 닫아 포트를 비울 필요가 있습니다. 방법? read()를 참조하십시오. 파일 끝을 읽을 때 (FIN이 수신됨을 의미), 0이 리턴됩니다.

3

클라이언트가 연결을 종료합니다.

클라이언트와 서버 모두 소켓을 닫고 종료해야합니다. 클라이언트가 클로즈를 끝내지 못했습니다 (가능성이 있습니다 - 파이널 라이저가 실행되었으므로) 또는 서버가 소켓을 종료하지 않습니다 (가능성이 높음).

using (Socket s = new Socket(/* */)) { 
    /* Do stuff */ 
    s.Shutdown(SocketShutdown.Both); 
    s.Close(); 
} 
+0

소켓은 사용 (..) 블록의 일부로 닫혀 있습니다. 그러나 현재는 .Shutdown 및 .Close를 명시 적으로 수행하지 않습니다. 일반적인 테스트에서는 문제가되지 않습니다. 서버는 우리가 찾을 수있는 모든 코드 경로에서 명시 적으로 둘 다 수행합니다 (비동기이기 때문에 복잡합니다). –

+0

@Kieran - 서버 프로세스를 수신 거부하면 CLOSE_WAITs가 지워진다는 사실은 내가 어딘가에서 닫히지 않는다는 것을 나타냅니다. –

-2

CLOSE_WAIT 년대는 소켓이 닫힌 후 이전의 접속을 다시 사용하여 동일한 소켓 번호 및 패킷 수신을 방지하기 위해, 잠시 동안 중단하는 것을 의미한다. huuuuge 번호의 소켓을 열고 닫는 경우에만이 작업을 수행 할 수 있습니다.

EDIT - 위의 CLOSE_WAIT가 아닌 TIME_WAIT이어야합니다.

+0

어떤 이유로 연결이 쐐기로 고정되는 경우 이보다 더 오래 걸릴 수 있습니다. http://blog.zhuzhaoyuan.com/2009/03/a-word-on-time_wait-and-close_wait/. TIME_WAIT와 같은 자연스러운 것이 아닙니다. –

+0

close_wait 및 time_wait이 혼란 스럽거나 혼란스러운가요? – Chris

+1

크리스 (TIME_WAIT)를 생각하고 있습니다. –

0

클라이언트에게만 TCP 소켓을 닫지 않아야합니다. 클라이언트 프로세스/기계가 충돌하면 어떻게됩니까?

일정 시간이 지난 후에 연결된 소켓에서 트래픽이 수신되지 않으면 서버에 의해 닫히지 않도록 시간 제한을 설정하는 것이 가장 이상적입니다.

5

서버에 CLOSE_WAIT 소켓이 누적되면 연결이 완료되면 소켓을 닫지 않습니다. Chris의 게시물에 대한 설명에서 상태 다이어그램을 살펴보면 CLOSE_WAIT은 소켓이 닫히고 FIN이 전송 된 후에 LAST_ACK으로 전환된다는 것을 알 수 있습니다.

비동기 특성으로 인해이를 수행 할 위치를 결정하는 것이 복잡하다고합니까? 이것은 문제가 아니어야합니다. recv의 콜백이 0 바이트를 반환하면 소켓을 닫아야합니다 (클라이언트가 연결의 측면을 닫으면 아무 것도 할 수 없다고 가정). 보내기를 계속하는 것에 대해 걱정할 필요가 있다면 여기에서 종료 (recv)를 수행하고 클라이언트가 종료했음을 메모하십시오. 일단 작업이 완료되면 종료 (보내기) 및 닫기를 수행하십시오.

당신은 클라이언트가 닫혔다는 것을 나타내는 0을 반환하는 read로부터 콜백에 새로운 읽기를 발행 할 수 있으며 이것은 당신에게 문제를 일으킬 수 있습니까? 그림에서

0

소켓에 대한 모든 작업이 클라이언트에 의해 완료되고 소켓에서 더 이상 읽기 작업을 수행 할 필요가 없어도 클라이언트는 닫기 명령을 실행해야합니다.

이 close 명령은 단순히 리스너 (서버)에게 연결을 종료해야한다고 말합니다.

간단히 말해서 서버가 비동기 모드에서 읽기 명령 (listener.read() 또는 listener.beginread (...))을 다시 발행하면 read는 0 바이트 읽기를 반환하며 이는 소켓의 다른 작업이 클라이언트에 의해 중지되었으므로 소켓을 리스너가 닫아야합니다.