2014-04-10 2 views
0

Microsoft's I/O Completion Port (IOCP) 메커니즘을 사용하여 비동기 네트워크 소켓 통신을 관리하는 서버 응용 프로그램이 있습니다. 일반적으로이 IOCP 접근법은 내 환경에서 매우 잘 수행되었습니다. 그러나 지침을 구하는 모범 사례 시나리오가 발생했습니다.완료 패킷을 사용할 수있을 때 I/O 완료 포트가 차단되지 않도록하려면 어떻게해야합니까?

테스트를 위해 제 서버 응용 프로그램은 기가비트 LAN을 통해 단일 클라이언트에게 데이터를 스트리밍합니다 (~ 400KB/초). 모든 것이 정상입니다 ... 클라이언트의 이더넷 케이블을 LAN에서 분리 할 때까지. 이 방식으로 케이블을 연결 해제하면 서버가 클라이언트가 사라 졌다는 것을 즉시 감지 할 수 없습니다 (예 : 클라이언트의 TCP 네트워크 스택이 서버에 대한 연결 종료 통지를 보내지 않음)

한편 서버는 계속 WSASend 클라이언트는 ... 이러한 호출이 비동기 적이기 때문에 "성공"(즉, 데이터가 소켓의 아웃 바운드 대기열에있는 OS에 의해 버퍼링 됨) 인 것처럼 보입니다.

이 모든 일이 발생하는 동안 GetQueuedCompletionStatus에 차단 된 16 개의 스레드가 있으며 포트에서 완료 패킷을 검색 할 때까지 기다리는 중입니다. 클라이언트 케이블을 연결 해제하기 전에 끊임없이 완료 패킷을 처리합니다. 자, 모든 것이 (예상대로) 약 32 초 동안 중단 된 것 같습니다. 32 초 후에 IOCP는 null이 아닌 lpOverlapped 값을 사용하여 FALSE을 반환하는 동작으로 돌아옵니다. GetLastError은 121을 반환합니다 (세마포어 시간 초과 기간이 만료되었습니다.) 나는 오류 121이 클라이언트가 사라진 것으로 결정한 후에 WSASend의 최종 결과가 아님을 가정 할 수 있습니다.

내 클라이언트가 사라 졌음을 알기 위해 32 초가 걸리는 네트워크 스택을 사용해도됩니다. 문제는 시스템이 이러한 결정을 내리는 동안 IOCP가 마비된다는 것입니다. 예를 들어, 동일한 IOCP에 게시하는 WSAAccept 이벤트는 오류 완료 패킷 (오류 121을 나타냄)이 수신 될 때까지 GetQueuedCompletionStatus에서 차단 된 16 개의 스레드 중 하나에서 처리되지 않습니다.

이 문제를 해결하기위한 초기 계획은 WSASend을 호출 한 직후에 WSAWaitForMultipleEvents을 사용하는 것이 었습니다. 소켓 이벤트가 (예 : 3 초) 신호되지 않으면 소켓 연결을 종료하고 계속 이동합니다 (IOCP의 광범위한 차단 효과를 방지하기 위해). 불행히도, WSAWaitForMultipleEvents 결코 시간 초과가 발생하지 않는 것 같습니다 (비동기식 소켓은 비동기식으로 미시적으로 신호를 받습니까? 아니면 TCP 큐로 데이터를 복사하면 신호를받을 수 있습니까?)

저는이 모든 것을 정렬하려고합니다. 그러나 누군가가 IOCP 중단을 방지하는 방법에 대한 통찰력을 가지기를 바랬습니다.

기타 세부 정보 : 내 서버 응용 프로그램은 Win7에서 8 코어로 실행됩니다. IOCP는 최대 8 개의 동시 스레드를 사용하도록 구성됩니다. 내 스레드 풀에 16 개의 스레드가 있습니다. 충분한 RAM, 프로세서 및 대역폭.

귀하의 제안과 조언에 미리 감사드립니다.

+1

이것은 올바르게 들리지 않습니다. 'WSAAccept()'는 먼저 처리되는 WSASend()에 의존하지 않습니다. 특히 두 개의 함수가 두 개의 분리 된'SOCKET' 핸들에서 호출되기 때문에 특히 그렇습니다. 'WSAAccept()'에 보류중인 클라이언트가 있으면, WSASend()가 백그라운드에서 계속 작동하는 동안 IOCP 이벤트를 게시합니다. 이것은 내가 당신이 올바르게 IOCP를 관리하지 않는다고 생각하게 만듭니다. 실제 코드를 보여주십시오. –

+1

나는 IOCP가 아마도 그렇게 부러지지 않기 때문에 당신의 코드에 버그가 있다고 생각한다. 몇 줄에 간단한 repro를 만들고 여기에 게시하십시오. 내 추측 : 과정에서 버그를 직접 발견 할 것입니다. – usr

+0

제안 해 주셔서 감사합니다. 사실,이 질문은 가짜로 판명되었습니다. 알 수 없지만 실제로는 두 개의 IOCP가 혼합되어 있습니다 (하나는 동일한 스레드 코드를 사용하는 동료가 추가했습니다). 이 두 IOCP 간의 상호 작용으로 인해 잘못된 동작이 발생하는 교착 상태가 발생했습니다. 이제 모든 것이 아름답게 작동합니다. – charunnera

답변

1

이 상황에서 WSASend() 완료가 지연되는 것이 일반적입니다. TCP 스택이 재전송 시도를 타임 아웃하고 미해결 상태 인 모든 미해결 전송을 완료 할 때까지 사용자를 얻지 못합니다. 이 작업은 다른 작업을 차단하지 않습니다. 내가 잘못 테스트하거나 코드에 버그가있을 것으로 예상됩니다.

'수정'에 결함이 있습니다. 보낸 사람이 소비자가 소비 할 수있는 것보다 빨리 보내는 경우 정상 연결 중에 언제든지이 '지연된 보내기 완료'상황을 볼 수 있습니다. this article on TCP flow control and async writes을 참조하십시오.더 좋은 계획은 허용하려는 쓰기 작업의 양을 계산하는 카운터를 사용하고 카운터가 도달하면 전송을 중지 한 다음 '낮은 물 마크'임계 값 이하로 떨어지면 다시 시작하는 것입니다.

네트워크 케이블을 컴퓨터에 꽂은 경우 다른 작업을 어떻게 완료 할 것으로 예상합니까? 읽기는 단지 거기에 앉아서 쓰기가 실패하면 실패하고 AcceptEx는 거기 앉아서 상태를 스스로 교정 할 때까지 기다립니다.

+0

안녕하세요,이 상황에서 'WSASend'스톨에 대한 귀하의 확인을 보내 주셔서 감사합니다. – charunnera

+0

이상한 행동의 원인 : 동료가 알고 있지 않은 보조 IOCP를 추가했습니다. 함께, 그들은 두통 시나리오를 일으킨 교착 상태를 가능하게했습니다. 코드를 수정했는데 모든 것이 이제는 별다른 효과를냅니다. 귀하의 의견과 귀하의 웹 사이트에서 제공 한 멋진 기사에 다시 한 번 감사드립니다. – charunnera

+0

BTW :이 질문을 게시하기 전에 Google을 통해 흐름 제어 도움말을 보았습니다. 잘 작성되었습니다. 내 프로젝트는 흐름 제어를 사용할 예정이지만 아직 구현하지 않았습니다. 또한, 어떤 네트워크 케이블을 뽑았는지 명확히하지 못해 사과드립니다. ClientA의 케이블을 당겨서 ClientB와 서버의 네트워크를 그대로 유지했습니다. 보내 주신 의견에 다시 한 번 감사드립니다. – charunnera

관련 문제