tcp socket server가 부적합 할 때까지 시간이 지남에 따라 close_waits를 구축합니다.

StackOverflow https://stackoverflow.com/questions/679643

문제

우리가 조사가 갈 수있는 한 누군가가 우리를 도울 수 있기를 바랍니다.

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

시스템이 장기간 (일반적으로 일)에 걸쳐 무거운 부하를 받고 있다면 Close_wait 소켓은 서버 상자 (Netstat -a)에 추가 연결이 더 이상 연결되지 않을 정도로 쌓입니다. . 그 시점에서 우리는 프로세스를 튕겨 야하고 다시 실행됩니다.

우리는 ASP.NET 응용 프로그램의 일부로드 테스트를 실행하여 문제를 복제하려고 시도했습니다 (코드의 일부 문제가 불가능하기 때문에). 우리는 우리가 이것을 관리하고 결국 Wireshark로 끝났다고 생각합니다. 패킷 트레이스 소켓 서버의 로그에서 Socketexception으로 나타나는이 문제의 다음과 같습니다.

System.net.sockets.socketexception : system.net.net.sockets.socket.beginsend (byte [] 버퍼, int32 오프셋, int32 크기, 소켓 플래그 소켓 플래그, asynccalbback 콜백, 객체 상태)에서 원격 호스트가 기존 연결을 강제로 닫았습니다.

패킷 트레이스에서 문제를 소켓 서버와 직접 대화하는 단일 스레드 프로세스 (ASP.NET 앱과 동일한 코드 사용)로서 문제를 재현하려고 노력했으며 불가능합니다.

우리가 잘못하고있는 일을 시도하거나 확인하거나 명백한 일을 할 다음 사항에 대한 제안이 있습니까?

도움이 되었습니까?

해결책

다이어그램을보십시오

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

클라이언트는 FIN을 서버 소켓으로 보낸 Close ()을 호출하여 연결을 닫았습니다.이 상태는 FIN과 상태가 Close_Wait로 변경되었으며 서버가 해당 소켓을 호출하지 않으면 그런 식으로 유지됩니다.

서버 프로그램은 클라이언트가 연결을 중단했는지 여부를 감지 한 다음 즉시 포트를 확보하기 위해 닫아야합니다. 어떻게? read ()를 참조하십시오. 파일 종료 끝 (지느러미가 수신되면)을 읽으면 0이 반환됩니다.

다른 팁

서버가 누적되는 경우 CLOSE_WAIT 소켓은 연결이 완료되면 소켓을 닫지 않습니다. Chris의 게시물에 대한 의견에서 상태 다이어그램을 살펴보면 CLOSE_WAIT 전환 LAST_ACK 소켓이 닫히면 FIN 전송 된.

비동기 특성으로 인해이 작업을 수행하는 것이 복잡하다고 말합니까? 이것은 문제가되지 않아야합니다. RECV의 콜백이 0 바이트를 반환하면 소켓을 닫아야합니다 (클라이언트가 연결 측면을 닫으면 할 일이 없다고 가정). 계속해서 보내는 것에 대해 걱정 해야하는 경우 여기에서 종료 (RECV)를 수행하고 고객이 닫았다는 점에 유의하십시오. 일단 셧다운 (송신)과 닫기를 마치면 마감됩니다.

클라이언트가 닫았다는 것을 나타내는 반환 0을 반환하는 읽기에서 콜백에서 새 읽기를 발행하고있을 수 있습니다. 이로 인해 문제가 발생할 수 있습니까?

클라이언트는 연결을 닫는 일을 담당합니다.

클라이언트와 서버 모두 소켓을 닫고 종료해야합니다. 클라이언트가 닫기를 완료하지 않거나 (최종화기 실행 중이므로 가능하지 않음) 서버가 소켓을 종료하지 않습니다 (가능성).

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

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

이상적으로는 일정 시간 후에 연결된 소켓에서 트래픽이 수신되지 않으면 서버에 의해 닫히도록 시간 초과가 제자리에 있어야합니다.

소켓의 모든 작업이 클라이언트에 의해 완료되었을 때 어떤 일이 발생하든 소켓에서 더 이상 읽기 작업을 수행 할 필요가 없으므로 클라이언트는 가까운 명령을 내려야합니다.

이 근접 명령 발행은 단순히 청취자 (서버)에게 연결을 종료해야한다고 말합니다.

간단한 단어로 서버가 다시 읽기 명령 (Async 모드에서 reader.read () 또는 threyeer.beginread (...)를 다시 발행하면 읽기가 0 바이트를 반환하면 소켓이 필요함을 나타냅니다. 소켓의 다른 작업이 클라이언트에 의해 중단되었으므로 청취자가 닫아야합니다.

Close_wait 's는 소켓이 닫힌 후 잠시 동안 매달려 동일한 소켓 번호를 재사용하고 이전 연결로부터 패킷을 수신하지 않도록합니다. 이렇게하면 huuuuge 수의 소켓을 정말 빨리 열고 닫는 경우에만 슬픔을 줄 수 있습니다.

편집 - 위의 Close_wait이 아닌 Time_wait 여야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top