정리

GetQueuedCompletionStatus의 0 transferred bytes (5)

저장소/VC++

출처 : http://blog.naver.com/winjks/10014283819


걍 참고해서 보자.

client연결 상태를 getpeername를 사용해서 확인해보는 것도 나쁘지 않을듯.


손님





올리기IOCP를 사용한 소켓에서의 클라이언트 소켓의 종료 감지...올려짐: 2004-07-05 23:36
인용과 함께 답변 이 게시물을 del.icio.us에 추가

안녕하세요... 눈팅만 하다 궁금한 사항이 있어 자문을 구합니다. 

iocp를 사용해 접속된 클라이언트의 종료를 인지하는 부분에서 접속이 종료된 클라이언트를 
100% 감지 할수 있는 방법이 있는지 궁금합니다. 

지금 사용하는 방법은 접속된 모든 클라이언트는 항상 ReadFile로 읽기 대기 상태로 만들어 놓고, 
필요시 WriteFile을 호출하고 있으며, 워커쓰레드를 몇개 만들어 GetQueuedCompletionStatus 호출에서 리턴되는 값으로 접속 종료를 판단하고 있습니다. 
그런데..... 간혹 클라이언트가 접속이 종료 되었는데 iocp에서 감지가 되지 않는 경우가 있습니다. 
컴퓨터 사양이 낮은경우 접속 끊김을 감지 하지 못하는경우가 더 많은듯 하구요. 

이전 iocp를 사용하지 않을경우에는 클라이언트 소켓마다 송수신시 시간을 저장해 일정 시간동안 통신이 이루어지지 않은 소켓의 경우 살아있는지 패킷을 전송시켜서 사용했었는데...진정 iocp에서도 이방법을 사용해야 하나요 ? 아니면 제가 iocp를 잘못 사용하고 있는건가요? 

여러분들은 어떤 방법을 사용하고 계신지 의견 듣고 싶습니다.
위로
 
symlink



가입: 2004년 6월 1일
올린 글: 31

올리기Re: IOCP를 사용한 소켓에서의 클라이언트 소켓의 종료 감지...올려짐: 2004-07-06 09:00
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
안녕하세요... 눈팅만 하다 궁금한 사항이 있어 자문을 구합니다. 

iocp를 사용해 접속된 클라이언트의 종료를 인지하는 부분에서 접속이 종료된 클라이언트를 
100% 감지 할수 있는 방법이 있는지 궁금합니다. 

지금 사용하는 방법은 접속된 모든 클라이언트는 항상 ReadFile로 읽기 대기 상태로 만들어 놓고, 
필요시 WriteFile을 호출하고 있으며, 워커쓰레드를 몇개 만들어 GetQueuedCompletionStatus 호출에서 리턴되는 값으로 접속 종료를 판단하고 있습니다. 
그런데..... 간혹 클라이언트가 접속이 종료 되었는데 iocp에서 감지가 되지 않는 경우가 있습니다. 
컴퓨터 사양이 낮은경우 접속 끊김을 감지 하지 못하는경우가 더 많은듯 하구요. 

이전 iocp를 사용하지 않을경우에는 클라이언트 소켓마다 송수신시 시간을 저장해 일정 시간동안 통신이 이루어지지 않은 소켓의 경우 살아있는지 패킷을 전송시켜서 사용했었는데...진정 iocp에서도 이방법을 사용해야 하나요 ? 아니면 제가 iocp를 잘못 사용하고 있는건가요? 

여러분들은 어떤 방법을 사용하고 계신지 의견 듣고 싶습니다.


GetQueuedCompletionStatus에서 반환되는 값이 FALSE일때만 처리하신듯.. 

처리가 완료되었더라도 처리된 데이터 크기가 0 이면 접속이 끊긴 상태입니다. 

대부분, 0바이트 짜리 데이터를 보내지 않는 다는 가정하게 내부에서 소켓의 끊긴 문제를 이런식으로 

반환하기도 합니다. 이런 식으로해서 다음과 같이 처리할수도 있습니다. (IOCP가 아닌 경우에) 

ioctlsocket( sock, FIONREAD, &nbytes) 

에서 nbytes 가 0인 경우도 소켓이 끊긴 상태입니다. 

참, UDP인 경우 0바이트가 발생된다고 소켓을 끊으면 안되겠죠^^; 

그럼..
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
sphawk



가입: 2004년 5월 28일
올린 글: 95
소속: Come back to Univ.

올리기접속 끊김.올려짐: 2004-07-06 10:16
인용과 함께 답변 이 게시물을 del.icio.us에 추가

랜선을 뽑는다던가. 갑자기 컴터가 재부팅이 되었다던가 하는 경우는 접속 끊어짐 감지가 안 될 수도 있습니다. 
전에 redwiki에서, ACE관련 글을 봤었는데, ACE도 저런 경우에는 ping check를 쓰라고 하더군요. 
(지금 찾으려니 wiki가 많이 개편되어서 찾을 수가 없더군요.) 

제 경험상으로도. 무슨 짓을 해도 ping check를 쓰지 않고, 접속 끊어짐 감지를 완벽하게 할 수는 없었습니다. 
.... 저거 때문에 피 본 일이 있기도 한데. 맨정신으로는 못할 말이고.. 

ps. ping check라는게. 다들 아시겠지만서도..(이동네는 운만 띄워도 아.. 그거.. 하는 동네라.) 
icmp ping을 쓰는 게 아니라.. 그냥 클라이언트가 작은 패킷 보내서.. 나 살아 있소 정도만 보내는.. 
서버는 받아서 다시 되돌려 보내고.. 양쪽 다, 일정 시간 동안 응답이 없으면 즐.. 시키는...
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
miracle2k



가입: 2003년 7월 9일
올린 글: 3

올리기Re: IOCP를 사용한 소켓에서의 클라이언트 소켓의 종료 감지...올려짐: 2004-07-06 10:37
인용과 함께 답변 이 게시물을 del.icio.us에 추가

symlink 씀:

GetQueuedCompletionStatus에서 반환되는 값이 FALSE일때만 처리하신듯.. 
처리가 완료되었더라도 처리된 데이터 크기가 0 이면 접속이 끊긴 상태입니다. 


의견 감사합니다 ^^ 
현재 저의 쓰레드 루프에서 처리하는 방법을 대충 적어 보면... 

loop 

if ( FALSE == GetQueuedCompletionStatus ) { 
if ( NULL != lpOverlapped ) { 
소켓 종료 처리... 
} else { 
쓰레드 종료.... 

} else { 
if ( 0 == dwBytesIO ) { 
소켓 종료 처리... 
} else 
if ( -1 == dwBytesID ) { 
쓰레드 종료... 
} else { 
정상처리.... 




위와 같이 되어 있고 지적해 주신 0 == dwBytesIO 부분은 처리를 하고 있습니다. 
symlink님 께서는 HearBeats(ping-pong )패킷을 클라이언트에 전송하지 않으시고도 iocp에서 발생하는 이벤트 만으로 모든 클라이언트가 관리되시는 건가요? m$에서 제공하는 iocp예제를 봐도 
소켓을 닫는 부분은 위의 부분과 Read,Write시 Pending오류를 제외한 오류에서 닫는것만 보이네요... 
별도로 클라이언트 소켓에 체크 패킷을 날려야 되는 방법만 있는지... 

기분학상.... 모든 클라이언트 소켓을 iocp에 등록하고 ReadFile시켜 놨으면... 클라이언트 종료시 읽기 오류가 발생하여 iocp에서 통보를 해줘야 될거 같은데,,,, iocp한테 무시당하고 있는 상황입니다... m$넘들이 물먹이는건지...
위로
사용자 정보 보기 쪽지 보내기 
miracle2k



가입: 2003년 7월 9일
올린 글: 3

올리기올려짐: 2004-07-06 10:46
인용과 함께 답변 이 게시물을 del.icio.us에 추가

앗... sphawk 님께서 글을 작성하는 도중에 답변을 ^^... 
저도 최후의 방법을 생각중인데... iocp가 그래도 뭔가를 해주지 않을까 하는 기대를 아직 버리지 못하고 있습니다...^^;
위로
사용자 정보 보기 쪽지 보내기 
일지매



가입: 2003년 11월 3일
올린 글: 40

올리기올려짐: 2004-07-06 10:53
인용과 함께 답변 이 게시물을 del.icio.us에 추가

포기하세요. 안해줍니다. 이건 iocp문제가 아니라 WAN의 문제죠.
_________________
정의구현!!
위로
사용자 정보 보기 쪽지 보내기 
symlink



가입: 2004년 6월 1일
올린 글: 31

올리기Re: 접속 끊김.올려짐: 2004-07-06 11:08
인용과 함께 답변 이 게시물을 del.icio.us에 추가

sphawk 씀:
랜선을 뽑는다던가. 갑자기 컴터가 재부팅이 되었다던가 하는 경우는 접속 끊어짐 감지가 안 될 수도 있습니다. 
전에 redwiki에서, ACE관련 글을 봤었는데, ACE도 저런 경우에는 ping check를 쓰라고 하더군요. 
(지금 찾으려니 wiki가 많이 개편되어서 찾을 수가 없더군요.) 

제 경험상으로도. 무슨 짓을 해도 ping check를 쓰지 않고, 접속 끊어짐 감지를 완벽하게 할 수는 없었습니다. 
.... 저거 때문에 피 본 일이 있기도 한데. 맨정신으로는 못할 말이고.. 

ps. ping check라는게. 다들 아시겠지만서도..(이동네는 운만 띄워도 아.. 그거.. 하는 동네라.) 
icmp ping을 쓰는 게 아니라.. 그냥 클라이언트가 작은 패킷 보내서.. 나 살아 있소 정도만 보내는.. 
서버는 받아서 다시 되돌려 보내고.. 양쪽 다, 일정 시간 동안 응답이 없으면 즐.. 시키는...


저 같은 경우는 님이 말씀하신 방식의 경우 불필요한 패킷을 보내야 되기 때문에.. 잘 사용하지는 않고 
다른 방법을 사용합니다. 

제가 리눅스에서 주로 개발해서 일단 리눅스 기준으로 말씀드리겠습니다. 

전제 조건: 접속된 소켓은 항상 데이터를 전송한다고 보고요.. 

처리: 
1. 최종 데이터 발생시간으로 부터 n 이상 데이터 발생이 없다면 소켓은 일단 차단(close) 
2. 전송중에 EAGAIN이 발생되는 경우 소켓 차단(close) 
: EAGAIN의 경우 상대방이 데이터를 받을수 없거나, 상대방이 소켓 버퍼에 데이터를 넣을수 없을때 
발생되는 오류 입니다. 
3. 데이터를 받을때, getpeername을 통해 소켓의 상태를 한번더 검사합니다. 
: 이경우는 중간에 소켓이 강제적으로 닫힌 경우나 내부에서 소켓을 폐쇄했는지 검사할때 사용합니다. 

그럼.
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
mastercho



가입: 2004년 5월 9일
올린 글: 213

올리기올려짐: 2004-07-06 11:42
인용과 함께 답변 이 게시물을 del.icio.us에 추가

예를 들면 
서버가 클라이언트의 메시지를 받아서 IOCP에서 리턴되어 메세지에 관한 작업을 처리하고 있습니다 

그런데 일이 끝나기도전에 
클라이언트에서 갑자기 접속을 끊어버리는 경우가 있을수 있는데 [connect reset 경우] 

그럴 경우 서버에서 전에 보낸 클라이언트 메세지 작업이 끝난후, 다시 iocp Request 요청을 하는 루틴에서 
io 요청 실패를 하게 됩니다 

따라서 IOCP 대기할때 0값을 리턴 받지 못하게 됩니다 

그래서 이런 인식하지 못하는 현상이 많이 발생하는것으로 보입니다
위로
사용자 정보 보기 쪽지 보내기 이메일 보내기 
비회원
손님





올리기올려짐: 2004-07-06 11:59
인용과 함께 답변 이 게시물을 del.icio.us에 추가

mastercho 씀:
예를 들면 서버가 클라이언트의 메시지를 받아서 IOCP에서 리턴되어 메세지에 관한 작업을 처리하고 있습니다 그런데 일이 끝나기도전에 클라이언트에서 갑자기 접속을 끊어버리는 경우가 있을수 있는데 [connect reset 경우] 그럴 경우 서버에서 전에 보낸 클라이언트 메세지 작업이 끝난후, 다시 iocp Request 요청을 하는 루틴에서 io 요청 실패를 하게 됩니다 따라서 IOCP 대기할때 0값을 리턴 받지 못하게 됩니다 그래서 이런 인식하지 못하는 현상이 많이 발생하는것으로 보입니다


역시 IOCP 문제가 아니고 구조적 결함을 가진 프로그램 문제입니다. IOCP의 worker 쓰레드에서 메시지에 관련된 작업을 직접하는건 대단히 좋지 않은 방법입니다. 쓰레드의 메시지 처리 시간이 길어지면 io 처리 효율이 낮아지게 되고 그 문제를 해결하기 위해서 worker 쓰레드가 많아지는 악순환을 초래하게 됩니다. 

그리고 IOCP는 커널 레벨의 Queue입니다.iocp request를 요청하는 루틴에서 io 요청 실패를 하게 된다는 말이 무슨 말인지 도저히 해석을 할수가 없네요.
위로
 
miracle2k



가입: 2003년 7월 9일
올린 글: 3

올리기올려짐: 2004-07-06 12:07
인용과 함께 답변 이 게시물을 del.icio.us에 추가

mastercho 님의 글에 궁금한것이 하나더 생겼네요 ^^; 

'iocp에 read시 소켓이 끊겨 있으면 iocp가 false를 리턴하지만 이미 read가 되어 대기중인 상태에서 소켓이 끊기면 iocp가 통보를 해주지 않는다' 라고 한다면... ReadFile, WriteFile시에 리턴되는 오류값으로 이미 소켓의 오류가 판단이 되고, 이때는 iocp에 등록이 되지 않을것이며,,, GetQueuedCompletionStatus 에서 false나 0 == dwBytesIO 되는 경우는 이미 Read,Write가 등록되어 대기중일때 리턴하는 값이 아닌가요? 
이렇게 본다면 iocp에서 대기중일때도 0이나 0 == dwBytesIO를 리턴한다고 봐야 될것 같은데.... 어떠신지...
위로
사용자 정보 보기 쪽지 보내기 
raonhaje



가입: 2004년 6월 22일
올린 글: 32
소속: 마이에트 엔터테인먼트

올리기올려짐: 2004-07-06 14:45
인용과 함께 답변 이 게시물을 del.icio.us에 추가

저역시 클라이언트 뻗음등으로 끊길때 서버에 남는 문제를 겪고있습니다. 
현재 해결방안은 어느기간동안 통신 없던 클라이언트들에게 패킷하나 보내보면 보내기 실패가 되면서 끊김처리를 할수 있더군요. 
약간 맘에 안들긴하지만 여튼 뾰족한 방법이 안보이네요.
위로
사용자 정보 보기 쪽지 보내기 글 올린이의 웹사이트 방문 
sphawk



가입: 2004년 5월 28일
올린 글: 95
소속: Come back to Univ.

올리기sparrowhawk올려짐: 2004-07-06 14:49
인용과 함께 답변 이 게시물을 del.icio.us에 추가

mastercho 씀:
예를 들면 
서버가 클라이언트의 메시지를 받아서 IOCP에서 리턴되어 메세지에 관한 작업을 처리하고 있습니다 

그런데 일이 끝나기도전에 
클라이언트에서 갑자기 접속을 끊어버리는 경우가 있을수 있는데 [connect reset 경우] 

그럴 경우 서버에서 전에 보낸 클라이언트 메세지 작업이 끝난후, 다시 iocp Request 요청을 하는 루틴에서 
io 요청 실패를 하게 됩니다 

따라서 IOCP 대기할때 0값을 리턴 받지 못하게 됩니다 

그래서 이런 인식하지 못하는 현상이 많이 발생하는것으로 보입니다


... 저같은 경우에는, iocp Request ( WSASend나 WSARecv 이겠군요. ) 에서 실패하면 소켓 닫게 짰습니다. 
소켓 닫혀 있으면 나중에 연결 셋에서 제거하고.. 
만일 끊김 인식 못하는 부분이 저거뿐이였다면 얼마나 좋았겠습니까 T_T;; 

참고로.. io pending 이 성공하면 ( WSASend, WSARecv등이 성공하거나 
WSA_IO_PENDING 이외의 에러를 뱉지 않으면.. ) 
작업이 실패하더라도, 반드시 GetQueuedCompletionStatus에 옵니다. 
MSDN에서 확실히 온다고 했으니 오겠지요 ;;; 

... 그런데 그 비정상 접속 끊김은 WSARecv 걸어놓은게 하염없이 기다려도 오지를 않지요;; 
나중에 소켓 끊으면 그때서야 '작업 실패여~' 하고 오니.. 

아마도 hardly closure를 한다던가, 랜선이 뽑힌다던가 하면서 FIN이 날아가서 그런 거 같기도 하고. 
에구구. 나중에 TCP/IP 프로토콜이나 좀더 공부 좀 해야겠군요. 그럼 말빨이 달려서 이만..
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
Testors



가입: 2003년 7월 26일
올린 글: 451
소속: (주)nFlavor

올리기올려짐: 2004-07-07 01:10
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
역시 IOCP 문제가 아니고 구조적 결함을 가진 프로그램 문제입니다. IOCP의 worker 쓰레드에서 메시지에 관련된 작업을 직접하는건 대단히 좋지 않은 방법입니다. 쓰레드의 메시지 처리 시간이 길어지면 io 처리 효율이 낮아지게 되고 그 문제를 해결하기 위해서 worker 쓰레드가 많아지는 악순환을 초래하게 됩니다.


어짜피 메시지 처리를 못할거라면 IO 에서 recv 한다해도 소용 없을듯 한데요? 
처리속도가 recv 속도를 못따라가 준다면 버퍼에 쌓이기만 할텐데요.. 
쌓아놓고 처리를 못하느니 받지 않는게 나을듯 합니다. 

그리고 제 생각으로는 IOCP의 worker 쓰레드에서 메시지에 관련된 작업을 직접 하지 않는것은 IOCP 를 제대로 쓰는 방법(쓰레드 풀링을 통한 SMP 활용)이 아닌듯 합니다..
위로
사용자 정보 보기 쪽지 보내기 이메일 보내기 글 올린이의 웹사이트 방문 MSN 메신저 
ICQ 번호
비회원
손님





올리기Re: sparrowhawk올려짐: 2004-07-07 10:22
인용과 함께 답변 이 게시물을 del.icio.us에 추가

sphawk 씀:

아마도 hardly closure를 한다던가, 랜선이 뽑힌다던가 하면서 FIN이 날아가서 그런 거 같기도 하고. 
에구구. 나중에 TCP/IP 프로토콜이나 좀더 공부 좀 해야겠군요. 그럼 말빨이 달려서 이만..


랜선이 뽑히든가 하는 문제로 네트웍 인식 못하는 문제는 TCP/IP의 문제이지 IOCP의 문제가 아닙니다 

따라서 TCP/IP 소켓를 사용하는 모든 서버는 그런 종류의 연결이 끊였는지 감지 하지 못합니다
위로
 
비회원
손님





올리기결국 IOCP 비정상 처리는 어떻게...?올려짐: 2006-09-12 16:46
인용과 함께 답변 이 게시물을 del.icio.us에 추가

이 쓰레드를 쓰신분은 결론을 어케 내셨는지 궁금하네요. 

역시 비정상 종료 처리로 지금 머리를 굴리고 있는중입니다만, Alive Ping 이외에 다른 방법이 없는것 

같기도 하고.. 


결국은 현재 접속하고 있는 connection들에 대해 주기적으로 Pint Time Check를 해야 하는 것일까요. 

모든 connection에 대한 주기적 검사란게 이벤트 방식의 IOCP의 구조에 안맞는것 같은데, 

좀 우아한 방법이 없을까 고민이 됩니다. 


고민하다가 SIO_KEEPALIVE_VALS 라는 소켓 옵션을 사용해볼까 해서 테스트 해봤는데 

무언가 잘못됐는지 제대로 동작을 안하네요. 

열린 connection에 SIO_KEEPALIVE_VALS 5초 옵션을 주고 연결된 클라이언트의 랜선을 확~ 

뽑았는데, 5분이 지나도 감지 못합니다. -0-;;;; 


혹시 이것을 IOCP에서 테스트 해보시거나 사용해 보신분도 의견을 주시면 감사하겠습니다.
위로
 
비회원
손님





올리기Alive Ping만이 확실한 방법일듯..올려짐: 2006-09-19 12:15
인용과 함께 답변 이 게시물을 del.icio.us에 추가

다만...효율적인 Heartbeat 전송 방법을 생각해야겠죠. 

제경우는... 

클라이언트에서 패킷전송할때 매번 비트타임을 현재시간으로 초기화 하면서, 핑을 보낼 시간이 경과하면(정해진 몇초동안 패킷전송이 없을때) 전송. 훔..캐주얼게임이라 UDP소켓이 쓸데가 꽤 있는지라(방목록갱신 등에 좋음)..어차피 생성되 있는 UDP패킷으로 전송. 

서버에서는 받은 패킷을 궂이 recv큐에 넣을 필요없이 worker쓰래드 단에서 시간재서 차단. 
너무 기본적인건가요?..ㅎㅎ
위로
 
비회원
손님





올리기스피트핵 체크 루틴들은 안넣으시나요?올려짐: 2006-09-19 14:01
인용과 함께 답변 이 게시물을 del.icio.us에 추가

저같은 경우는 주기적으로 서버와 클라이언트간에 타임스탬프를 찍어 교환하는 방식으로 
스피드핵을 걸러내고 있습니다. 각 클라이언트별 핑타임까지 고려해서 걸러내보니 
국내 환경에서 110%까지는 선의의 피해자 없이 잘 돌아가는 것으로 파악됩니다. 
어차피 이렇게 주기적으로 패킷을 주고 받다보니 
이녀석을 활용해서 Keep Alive 체크도 하고 있습니다. 
최대 1분동안 응답이 없으면 죽은 클라이언트로 간주하고 있습니다. 
물론 중간에 로딩 타임 등에 대한 고려가 필요합니다.
위로
 
myevan



가입: 2003년 3월 4일
올린 글: 976

올리기Re: 스피트핵 체크 루틴들은 안넣으시나요?올려짐: 2006-09-19 14:23
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
저같은 경우는 주기적으로 서버와 클라이언트간에 타임스탬프를 찍어 교환하는 방식으로 
스피드핵을 걸러내고 있습니다. 각 클라이언트별 핑타임까지 고려해서 걸러내보니 
국내 환경에서 110%까지는 선의의 피해자 없이 잘 돌아가는 것으로 파악됩니다. 
어차피 이렇게 주기적으로 패킷을 주고 받다보니 
이녀석을 활용해서 Keep Alive 체크도 하고 있습니다. 
최대 1분동안 응답이 없으면 죽은 클라이언트로 간주하고 있습니다. 
물론 중간에 로딩 타임 등에 대한 고려가 필요합니다.


쓰레드 논외지만 스피드핵 이야기가 나와서... 
컴퓨터 시계들이 그리 정확하지 않기 때문에 
주기적으로 시간 동기화 프로토콜을 사용하시는 것이 좋습니다. 

제가 사용한 방법중 가장 효과가 좋았던 것은 
그냥 스피드핵을 인정하고 속도가 빨라진 만큼 데미지에 패널티를 주는 방식입니다. 
(한번 공격할 시간에 두번 공격했다면 1/2 데미지) 

어차피 게임에서 공격은 일정한 랜덤 범위가 있기 마련인데 
여기에 게임 외적인 요소 - 즉 네트워크 렌턴시 - 요소를 추가시키는 것이죠. 

300~400밀리초 간격으로 떨어져있던 패킷이 몰아서 오는 경우는 극히 드물기 때문에 
게임이나 유저 개개인에게 크게 지장은 주지 않으면서 상당히 공평한 결과를 얻을 수 있습니다.
_________________
빗자루네 http://www.myevan.net >_<b
위로
사용자 정보 보기 쪽지 보내기 글 올린이의 웹사이트 방문 
laster40



가입: 2005년 1월 12일
올린 글: 98
소속: 무소속

올리기Re: 결국 IOCP 비정상 처리는 어떻게...?올려짐: 2006-09-21 03:41
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:


고민하다가 SIO_KEEPALIVE_VALS 라는 소켓 옵션을 사용해볼까 해서 테스트 해봤는데 

무언가 잘못됐는지 제대로 동작을 안하네요. 

열린 connection에 SIO_KEEPALIVE_VALS 5초 옵션을 주고 연결된 클라이언트의 랜선을 확~ 

뽑았는데, 5분이 지나도 감지 못합니다. -0-;;;; 


혹시 이것을 IOCP에서 테스트 해보시거나 사용해 보신분도 의견을 주시면 감사하겠습니다.



sio_keepalive_vals -_-옵션 켜구 하면 보통 로컬에선 감지가 될텐데^^;;; 


rfc문서에 keepalive 는 기본구현사항(용어가 있잖아요? 꼭 구현해야 한다는 뭐 그런;; )이 아닙니다. 
권장 사항(recommand? - rfc문서들의 레벨이 있던데 정확히 모르겟군요;; )이죠...그래서 네퉉크 장비를 만드는 사람이... 좀 바쁘시면 안만들어두 되는 그런것이죠 아무리 옵션을 세팅했다고 해서... 될일은 아니죠 모든 장비가 keepalive을 지원하는 그런일은 바라지 않는것이...;; 

랜카드가 어떤건지 모르겟으나 제 경험상 로컬에서 저 옵션을 켠것고 끈것은 확실히 차이가 있었습니다.-0-
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
laster40



가입: 2005년 1월 12일
올린 글: 98
소속: 무소속

올리기Re: 스피트핵 체크 루틴들은 안넣으시나요?올려짐: 2006-09-21 03:47
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
저같은 경우는 주기적으로 서버와 클라이언트간에 타임스탬프를 찍어 교환하는 방식으로 
스피드핵을 걸러내고 있습니다. 각 클라이언트별 핑타임까지 고려해서 걸러내보니 
국내 환경에서 110%까지는 선의의 피해자 없이 잘 돌아가는 것으로 파악됩니다. 
어차피 이렇게 주기적으로 패킷을 주고 받다보니 
이녀석을 활용해서 Keep Alive 체크도 하고 있습니다. 
최대 1분동안 응답이 없으면 죽은 클라이언트로 간주하고 있습니다. 
물론 중간에 로딩 타임 등에 대한 고려가 필요합니다.



저도 같은 방법으로 구현했습니다. 반가워서-0-;; 



|------------------------------|------------------------------|------------------------------|
^ ^ ^ ^ ^ ^


^에서 ^ 까지만 들어와 주면-_- 좋아요 라고 세팅해주고 벗어나면 누적시켜서 처리하고 있습니다~
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
비회원
손님





올리기ACE에 있는 Ping을 이용하라는 의미..올려짐: 2006-09-21 10:22
인용과 함께 답변 이 게시물을 del.icio.us에 추가

Ping을 이용하라는 의미가 클라에서 나 살아있소라는 패킷을 보내는거였습니까? 

서버에서 패킷을 성공적으로 보내고 
클라에서 받고 난 이후에 클라에서 랜선을 뽑는다던지 PC를 끈다던지 했을 경우, 
서버에서 다음 패킷을 날려야만 서버에서 연결끊김을 알수 있다. 

위와 같은 가정하에 서버에서 너 살아있냐라는 Ping패킷을 보내면 클라이언트 쪽 
연결이 종료됨을 알수 있기때문에 Ping을 보내라는 것으로 알고 있었는데 아닌가요?

GetQueuedCompletionStatus의 0 transferred bytes (4)

저장소/VC++

경험 부족이네, 확신이 없어 여기저기 퍼온다. ㅋ

긁어다 붙였는데 잘 붙네.. 원치 않는 것 까지.. ㅡㅜ


원문 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=722711&ref=722690



 iocp 서버만들때 클라이언트가 연결을 끊었을경우  | VC++ 일반2008-05-18 오후 10:16:41
정종현 (jjjjrr)  정종현님께 메시지 보내기정종현님을 내 주소록에 추가합니다.정종현님의 개인게시판 가기번호: 722690  / 읽음:143

안녕하세요

iocp 서버만들때

클라이언트가 연결을 끊었을경우

어떤이벤트가 발생하는지...

아래코드에서보면

if(dwBytesTrans == 0)   // 전송받은 것이 없다면 클라이언트가 종료한 경우
이경우가 클라이언트가 종료시의경우인데

bRet 가 false 이고

   ErrorCode = GetLastError();
   if (ERROR_NETNAME_DELETED == ErrorCode) 

인경우도 클라이언트의 연결이 끊어진경우라고하던데

이두경우의 차이점이 뭔가여?

 

 

  bRet = GetQueuedCompletionStatus(pIOCP->m_hIOCP, &dwBytesTrans, reinterpret_cast<ULONG_PTR*>(&pClient),
   reinterpret_cast<LPOVERLAPPED*>(&pIO), INFINITE);
  if(bRet)   // 에러상태를 점금한다
  {
   if((ULONG_PTR)pClient == THREAD_DIE)  // 스레드 강제종료
   {
          int ErrCode = WSAGetLastError();
    TRACE("IOCP 스레드 강제종료: %d\n", ErrCode);
       //pIOCP->CloseClient(pClient, FALSE);
    return FALSE;
   }
  }
  else
  {
   ErrorCode = GetLastError();
   if (ERROR_NETNAME_DELETED == ErrorCode) 

   {
   }
   continue;
  }

  if(dwBytesTrans == 0)   // 전송받은 것이 없다면 클라이언트가 종료한 경우
  {
   continue;
  }

이 글에 답변 등록하기
 [답변].2008-05-19 오전 12:02:01
박인규 (linuxian)  박인규님께 메시지 보내기박인규님을 내 주소록에 추가합니다.박인규님의 개인게시판 가기번호: 722698  

ERROR_NETNAME_DELETED은 IO작업중인 상태에서 접속이 끊긴 것입니다.

비정상적 종료라고 보시면 되겠구요.

 

recv 했을 때 버퍼의 크기가 0이라면 정상적인 종료로 보시면 됩니다.

 

이 글에 답변 등록하기
         [답변]클라이언트의 연결이 끊어진경우가2008-05-19 오전 7:22:09
정종현 (jjjjrr)  정종현님께 메시지 보내기정종현님을 내 주소록에 추가합니다.정종현님의 개인게시판 가기번호: 722710  

답변감사합니다

혹시 이두경우외에 클라이언트의 연결이 끊어진경우가

있을까여?

ERROR_NETNAME_DELETED 상태를 몰라서 한참헤멨는데

다른경우는 없을런지...

 

이 글에 답변 등록하기
 [답변].2008-05-19 오전 7:39:20
박인규 (linuxian)  박인규님께 메시지 보내기박인규님을 내 주소록에 추가합니다.박인규님의 개인게시판 가기번호: 722711  

GetQueuedCompletionStatus 이 함수가 거짓을 리턴되었다는 것은 요청한 IO 작업을 완료하지 못했다는 뜻입니다.

즉 IO 작업중에 또는 작업시도할때 상대편에 무슨 일이 생긴 것이지요.

왜냐하면 TCP는 기본적으로 연결을 보장하니까요.

이때 에러코드가 ERROR_NETNAME_DELETED 입니다. 솔직히 이건 문서에도 잘 나와있지 않은거라

저도 경험상 찾아낸 기억이 나네요.

 

 

GetQueuedCompletionStatus 은 TRUE를 리턴하면 IO작업을 완료했다는 뜻입니다.

Iocp에서 WSARecv를 걸어 두죠?

따라서 Recv에서 0바이트를 리턴(IO 완료)했다는 의미는 접속이 끊어진 걸로 간주하는 겁니다.

이것은 왜 그렇게 했느냐.. ㅎㅎ 처음 만든 사람이 그렇게 한거죠. 전송받은 바이트는 항상 0보다 클테니

0을 리턴하면 접속 종료로 하자 머 이런..

GetQueuedCompletionStatus의 0 transferred bytes (3)

저장소/VC++

음.. 요렇게도 쓰는구나. +ㅁ+

근데 내가 찾는 것과는 다르다.



원문 출처 : http://ykpk3733.egloos.com/8780



IOCP 를 공부중에 우연히 0 size buffer 란 기법을 알게 되고 여기저기 자료를 보면서 공부한 내용을 정리한것이다.

 

조금이라도 도움이 되었으면 하는 마음으로 포스팅을 한다.

 

-----------------------------------------------------------------------------------

1. "기본 WSAOVERLAPPED의 구조"

다음 구조체는 WSARecv() 혹은 WSASend() 함수에 넘겨주어야 하는 일반적인WSAOVERLAPPED 구조체이다.

 

typedef struct PER_IO_DATA : public WSAOVERLAPPED {
 char  Buffer[DATA_BUF_SIZE];
 int operation;
}PER_IO_DATA;

 

이 구조체에는 Buffer라는 변수가 포함되어 있다.

즉, 이것은 0 SIZE 버퍼가 아닌 클라이언트마다 각각의 버퍼를 할당해주는 방식이다.


2. "0 SIZE 버퍼"

1번과 같은 방식은 대량 연결용 서버의 경우엔 불필요한 메모리를 너무 많이 잡아 먹고, 관리도 힘들어진다.

이런 경우에는 "0 SIZE 버퍼" 를 이용하는 방법이 있다.

아래는 "0 SIZE 버퍼" 의 구조체 정보이다.

 

typedef struct PER_IO_DATA : public WSAOVERLAPPED {
 int operation; // OP_RECV, OP_SEND
}

 

보는바 와 같이 버퍼를 아예 제거 해버렸다.

그리고, 다음과 같이 사용 하면 된다.

 

pData = new PER_IO_DATA;
if( pData == NULL )
 return FALSE;

pData->Operation = OP_RECV;

wsabuf.buf = NULL; // 버퍼를 아예 제공하지 않는다.
wsabuf.len = 0;  // Recv할 최대 크기를 0으로 만든다.
flag = 0;
ret = WSARecv( sock, &wsabuf, 1, &&bytes, &flag, pData, NULL );
if( ret == SOCKET_ERROR && WSAGetLastError() != ERROR_IO_PENDING ){
 delete pData;
 return FALSE;
}

 

이렇게 하면, 해당 소켓으로 데이터가 들어왔을때 IOCP는 Worker thread를 깨워

처리하도록 한다. 그런데, 문제는 버퍼가 없으니 받은 데이터가 없다.

3. Worker thread에서 데이터 처리하기

아래 코드는 Worker thread의 핵심이 되는 함수이다.

 

ret = GetQueuedCompletionStatus(
 m_cp,    // IOCP Handle
 &bytes,    // 송,수신된 byte 수
 (LPWORD)&sock,   // Completion Key
 (LPWSAOVERLAPPED *)&pid, // WSAOVERLAPPED 데이터
 INFINITE );

 

3번째 PARAMETER인 sock은 Completion Key 로 SOCKET HANDLE 을 바로 사용한 경우이다.

일반적으로 bytes 값이 "0"이면 연결이 끊긴 것으로 처리를 하였다.

하지만 "0 SIZE 버퍼"를 사용했을 경우엔 무조건 bytes 값이 "0" 로 리턴된다.

따라서, 이 경우에는 끊긴 것으로 판단하지 말고 일단 데이타가 들어온 것이라고 판단해야 한다.

버퍼를 0로 만들었기 때문에 IOCP는 소켓으로 수신된 데이터를 아직 손대지 않은 상태이다.

이제 이것을 읽어 내야 하는데, 방법은 간단하다.

일반적인 송,수신 소켓 함수로 읽어내면 된다.

프로토콜을 이쁘게 정의하면, 수신되어야할 데이터가 얼마인지를 알 수 있는 경우가 있는데,

이 경우는 그 만큼 읽혀 질때까지 recv()를 하면되고,

만일 모를 경우는 nonblocking 방식으로 WSAEWOULDBLOCK이 될 때까지 recieve를 하면 된다.

이렇게 데이터를 모두 읽어서 처리하였다면,

다시 WSARecv() 를 사용하여 IOCP에 요청을 한다.

물론 생성된 pid는 이곳에서 제거를 해도 좋고, 계속 사용해도 좋다.


GetQueuedCompletionStatus의 0 transferred bytes (2)

저장소/VC++

음.. 


원문 출처 : http://copynull.blog.me/10078931630


네트워크 접속이 비정상으로 끊겼을 때는 
GetQueuedCompletionStatus()함수가 FALSE를 리턴하고 수신바이트 크기가 0(zero) 입니다. 

정상적으로 끊겼을 때는 
GetQueuedCompletionStatus()함수가 TRUE를 리턴하고 수신바이트 크기가 0(zero) 입니다. 
이 때 GetQueuedCompletionStatus()에서 Overlapped Recv I/O 가 리턴됩니다. 

 

비정상적종료 :   리턴값 false, 수신바이트 0

정상적인종료 :   리턴값 true,  수신바이트 0

 

즉 간단히 코드로 설명해보면

 

BOOL result = GetQueuedCompletionStatus(......);

 

if( result == FALSE || recvBytes == 0 )

{

        if( result == FALSE )

        {      비정상 종료 알려주는 코드  WSAGetLastError()로 알림   }

      // 정상 종료 코드

      // 종료를 진행한다....

}

 

IO_TYPE로 검사후 진행되는 코드의 경우 아래와 같이 진행하면 되겠다.

if ( !result || ( result && !recvBytes ) )
  {
   if (OverlappedEx->IoType == IO_ACCEPT)    // 데이터가 없어도 IO_ACCEPT라면 접속함수로 넘김
    OnIoConnected(Object);
   else                                                    // 그것도 아니면 완전 모두 에러처리
    OnIoDisconnected(Object);

   continue;
  }

GetQueuedCompletionStatus의 0 transferred bytes (1)

저장소/VC++

내가 틀리지 않았당께!! 아닌가? 



원문 출처 : http://javawork.egloos.com/2265358


 ERROR_NETNAME_DELETED는 에러 번호로는 64번이고 한글로는 "지정된 네트워크 이름을 더 이상 사용할 수 없습니다." 정도로 해석됩니다. 구글에 ERROR_NETNAME_DELETED로 검색해보면 거의 IOCP와 관련된 글들이 나옵니다. 어떤 상황에서 이 에러를 만나게 되는지, 해결책은 무엇인지 적어봅니다.

 보통 IOCP에서 소켓 끊어짐의 상징은 0 byte read 입니다. 0 byte read가 통보되는 시점은 상대방 소켓에서 closesocket() 혹은 shutdown() 함수를 호출한 시점입니다. 즉, 상대방이 closesocket() 혹은 shutdown() 을 호출하지 않고 종료해버리면 일반적으로 0 byte read는 발생하지 않습니다. 이렇게 0 byte read가 발생하지 않은 상태에서 read() 혹은 write()를 시도하면 상대는 이미 종료 되었으므로 ERROR_NETNAME_DELETED 에러가 나게 됩니다. 이러한 경우를 우아한 종료와는 반대되는 개념으로 HardClose라고 합니다.

ACE에서는 ACE_Asynch_Read_Stream.read() 나 ACE_Asynch_Write_Stream.write() 에서 0 이 아닌 다른 정수를 리턴하고(에러), ACE_OS::last_error() 하면 64번이 리턴됩니다. ACE를 사용하지 않는 경우에는 Read/Write 혹은 GetQueuedCompletionStatus에서  에러가 발생하고 GetLastError하면 64번이 리턴되겠죠.

다른 분의 설명으로는 accept에서도 발생가능한데, AccpEx호출 시 backlog에 있던 소켓이 accept가 되기 전에 접속을 끊어도 이 에러가 발생한다고 합니다.  아마도 이 글이 그러한 상황인 것 같습니다.

요약하면 ERROR_NETNAME_DELETED가 발생하는 경우는 상대방이 HardClose한 상황 이므로 그냥 종료처리하면 된다 입니다.