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, 프로세서 및 대역폭.
귀하의 제안과 조언에 미리 감사드립니다.
이것은 올바르게 들리지 않습니다. 'WSAAccept()'는 먼저 처리되는 WSASend()에 의존하지 않습니다. 특히 두 개의 함수가 두 개의 분리 된'SOCKET' 핸들에서 호출되기 때문에 특히 그렇습니다. 'WSAAccept()'에 보류중인 클라이언트가 있으면, WSASend()가 백그라운드에서 계속 작동하는 동안 IOCP 이벤트를 게시합니다. 이것은 내가 당신이 올바르게 IOCP를 관리하지 않는다고 생각하게 만듭니다. 실제 코드를 보여주십시오. –
나는 IOCP가 아마도 그렇게 부러지지 않기 때문에 당신의 코드에 버그가 있다고 생각한다. 몇 줄에 간단한 repro를 만들고 여기에 게시하십시오. 내 추측 : 과정에서 버그를 직접 발견 할 것입니다. – usr
제안 해 주셔서 감사합니다. 사실,이 질문은 가짜로 판명되었습니다. 알 수 없지만 실제로는 두 개의 IOCP가 혼합되어 있습니다 (하나는 동일한 스레드 코드를 사용하는 동료가 추가했습니다). 이 두 IOCP 간의 상호 작용으로 인해 잘못된 동작이 발생하는 교착 상태가 발생했습니다. 이제 모든 것이 아름답게 작동합니다. – charunnera