2009년 7월 10일 금요일

[socket] IOCP에서 합리적인 강제종료 방법

IOCP의 기본 규칙은, 하나의 세션에 대해 IO요청중인 상태에서는 이게 완료통보로 오기까지는

이 세션에 대해 다른 요청작업을 하면 안된다는 것이다



그렇다면 PostQueuedCompletionStatus(hcp, cbTransferred, ssid, p); 는 방법으로 적절하지 못하다



하나의 세션은 IO요청중이거나, 완료통보 된 상태에서 작업하여 다시 IO요청으로 가기전의 상태만 존재하기 때문이다

즉, 완료통보 상태가 되려면 반드시 client 측에서 뭔가 신호 하나를 던져줘야만 한다는 것이다



P.. 방법을 사용할 경우, IO요청중에 이루어진다면, 맨위에 기술한 기본 규칙에 어긋나므로 부적절

다음으로 작업중에 요청이 된다면, 하나의 세션에 대해 2개의 쓰레드에서 작업을 해버리므로 부적절(P.. 는 직접적 큐잉방법이므로 호출 즉시, G.. 로 뜨게됨)



그렇다면 방법은 두가지다... (효율적인 방법을 꼽는 다면)



1. 쓰레드에 안전한 ConnList 를 사용하는 방법

해당 struct에 bool disconn을 추가하여, 매 GQCS 호출시, 체크를 하여 true 일때는 transferred byte 를 0으로 바꿔서

자연스럽게 클라이언트의 종료 루틴으로 빠지게 하는 방법

장점: P... 보다는 루틴의 안정성이 뛰어남

단점: 클라이언트가 반드시 길이 有의 패킷을 보내야한다는점, 마지막에 완료 루틴으로 온 패킷이 drop(씹히는 상태)된다는점



2. closesocket을 사용하는 방법



하지만 이때 또 주의사항이 있다

1. c.. => IO요청 시작(중) 일때 : WSARecv 에러리턴즉시 처리가능

2. IO요청 시작(중) 일때 => c.. : 정상적인 완료통보로 뜸

3. c.. => 세션 작업중일때 : 다시 IO요청으로 가므로 : 1과 동일

4. c.. => 세션 종료 작업 중일때 : closesocket이 중복허용하지 않는다면 에러가 발생할 수도??? 아니라면 문제없음(IO요청이 더이상 안일어나므로)

5. c.. => 세션 종료 작업 이후에 요청될때 : 뭐, 없는 개체이므로 JUST OK (하지만 없는 개체에 대해 위의 함수를 허용하지 않는다면, 에러, 아니라면 문제 없음)

=> 확인 결과: 문제 없음

장점:

- 이미 워커쓰레드에서 close 루틴이 진행중이라 하더라도 delete ptr 및 push, ConnList erase 과정은 여기서만 담당하므로 상관없음

- 동일 socket에 대해 두번씩이나 closesocket를 호출한다하더라도 에러는 안걸림

- 워커쓰레드 함수상에서는 항상 IO요청이 이루어지도록 하고있으므로 아래 두가지 항목의 장점이 있음

- 세션에 대해 작업중일때는 WSARecv 호출 즉시 종료처리를 해주면 됨

- IO요청 중일때에는 자연스럽게 완료통보상으로 클라이언트의 FIN 핸드쉐이크의 결과 신호가 리턴됨

단점: 없음

주의사항: 이 방법을 사용하므로써, 어떤 에러가 일어나게 될지는 아직 검증되지 않은 상태임

- 이상이 없을 것이다: closesocket(sock) 에서 어짜피 sock은 전역변수가 아니니 상관은 없음

(IOCP 에서는 이미 어셉트 쓰레드와 워커 쓰레드가 나뉘어지므로, 하나의 유저의 accept와 동시에 다른 유저의 closesocket이 처리될 수 있음, 그렇다면, 딱히 이 부분은 동기화에 너무 과하게 신경쓰지 않아도 되는 부분일듯)
[출처] IOCP에서 합리적인 강제종료 방법|작성자 Harpy

댓글 없음:

댓글 쓰기

팔로어

프로필

평범한 모습 평범함을 즐기는 평범하게 사는 사람입니다.