서버와 클라이언트가 연결된 상태에서 클라이언트가 socket API로
접속을 끊던가 또는 클라이언트 프로그램이 종료하면 서버는 즉시 클라이언트의 접속 해제를 감지할 수 있습니다. 그러나
클라이언트가 특수한 상황에 빠졌던가 또는 클라이언트가 인터넷 선을 뺀 경우 일정 시간이 지날 때까지 서버에서는 접속이 끊어진 것을 감지할 수 없습니다.
이런 경우 socket API 옵션의 ‘KeepAlive’를 사용할 수도 있지만 대부분 서버와 클라이언트간에 주기적으로 패킷을 주고 받으면서 연결이
제대로 되어 있는지 확인을 합니다. 보통 이런 기능을 ‘HeartBeat’
기능이라고 부릅니다.
HalfNetwork에 ‘HeartBeat’와
같은 기능을 하는 것이 추가 되었습니다.
TestServer의 코드를 보면 서버의 환경 설정에서 config.ZombieConnectionTerm라는 것을 볼 수 있습니다. 이것은
ZombieConnectionTerm에 설정한 시간까지 클라이언트가 패킷을 보낸 적이 없으면 접속을
끊어버립니다.
ZombieConnectionTerm의 값은 밀리세컨드 단위를 사용합니다. 그리고 0을 설정하면 사용하지 않은 것으로 설정됩니다.
Proactor 방식에서
Connect를 하면 접속과 동시에 접속을 끊는 문제가 있었습니다. 이것은 앞서 이야기
했듯이 ACE와 VC++ 10의 문제입니다. 현재 ACE가 아직 VC++ 10을
지원하지 않고 있는 상황이라서 HalfNetwork에서는 동기 방식의
Connect 기능을 추가하여 문제를 일단 해결했습니다.
VC++ 9, 8 등에서는 기존과 같이 비동기나 동기 방식 어느 것이나
사용해도 괜찮지만 VC++ 10에서는 꼭 동기 방식의 Connect를
사용해야 합니다.
NetworkInstance에서 AsynchConnect
사용하면 비동기 연결을 사용하고, Connect를 사용하면 동기 연결을 사용합니다. 혼용하여 사용해도 괜찮습니다.
참고로 Proactor 에서는 비동기, 동기 연결을 선택할 수 있지만 Reactor에서는 동기 연결만을
사용할 수 있습니다.
HalfNetwork에 있는 테스트 서버와 클라이언트를 VC++ 10에서 빌드 후 실행 해보면 접속과 동시에 접속이 끊어집니다( 제 기억으로는 Beta1까지는 문제가 없었던 것 같습니다..).
이 문제에 대해서 Javawork님께 물어본 결과 정확하게는 HalfNetwork의 문제이기 보다는 ACE와 VC++ 10의 문제라고 합니다.
문제의 부분은 Proactor 방식에서 Async(비동기) 방식으로 Connect를 하면 접속과 동시에 끊어집니다. ACE에서도 동일한 문제가 발생하고 있다고 합니다.
현재 해결 방법은 VC++ 10을 사용하지 않던가(다른 버전에서는 문제가 없습니다), VC++ 10을 사용하는 경우Proactor 방식으로 사용하는
경우 Connect를 사용하지 말아야 합니다.
클라이언트에서 HalfNetwork를 사용하는 경우는 Reactor 방식을 사용해도 충분하기 때문에 큰 문제가 없지만 서버의 경우는
Proactor 방식을 사용해야 하는데, 서버 대 서버끼리 연결을 해야 하는 경우가 있기 때문에 VC++
10을 사용하는 경우는 꽤 문제가 크다고 생각합니다.
해결 방법은 두 가지가 있는 것 같습니다. 하나는 ACE 라이브러리를 만드는 측에서 이 문제를 해결해주는 것으로 그러면 자동으로 해결 됩니다. 두 번째는 HalfNetwork에서 Proactor 방식을 사용하여 Connect를 할 때 동기 방식으로
연결할 수 있는 기능을 제공하는 것입니다.
위에 제가 언급한 두 개의 방법 중 해결책이 나올 때까지 서버 대 서버가 연결되는 구조의 서버를 만드는 경우는 VC++ 10으로는 HalfNetwork를 사용하지 않는 것이 좋습니다.
아래는 Javawork님이 구글 그룹스에 올린 글입니다.
( http://groups.google.co.kr/group/halfnetwork?hl=ko )
AddTimer 메소드를 사용하면 타이머 기능을 사용할 수 있습니다.
bool AddTimer(uint32 timerID, uint32 interval, uint32 start = 0);
interval은 타이머의 주기(ms), start는 최초에 몇 ms후에 불릴지를 결정하는 인자 입니다.
start는 스킵하면 interval과 같은 값으로 설정됩니다.
예를 들어 아래와 같이 설정하면
NetworkInstance->AddTimer(100, 2000);
eMH_Timer 값이 2초에 한번씩 Queue에 넣어집니다.
TimerID는 postee.stream_id값으로 식별이 가능합니다.
특정 QueueID로만 PopMessage(혹은 PopAllMessage)를 하고 있으면 타이머 이벤트를 받을수 없습니다.
* QueueID 인자 없는 PopMessage(혹은 PopAllMessage) 함수를 사용하거나
* TimerQueueID로 PopMessage(혹은 PopAllMessage) 를 해야
타이머 이벤트를 받을수 있습니다.
TestServer 예제를 참고하시면 사용예가 있습니다.
또 하나의 변경 사항은 예전에는 QueueID 인자 없는 PopAllMessage를 사용하면
Queue에서 가져올게 없어도 cpu 사용률이 증가하는 현상이 있었는데 이번에 수정되었습니다.
여러개의 Queue를 하나의 이벤트 객체를 통해 감시 할수 있는 코드를 추가했기 때문입니다.
HalfNetwork를 만드신 영기님을 도와서 저는 문서화 작업을 해 볼려고 하는데
가장 원하는 것이 어떤 부분의 문서화인지 궁금합니다.
아무래도 저는 영기님을 통해서 이전부터 HalfNetwork에 대한 설명을 들어서
HalfNetwork를 처음 접하시는 분들이 어떤 부분이 사용하는데 불편함을 느끼는지 잘 모릅니다.
그러니 HalfNetwork를 사용하면서 이런 부분의 문서화가 있으면 좋겠다라고 생각하는 부분이 있으면
알려주시기 바랍니다.
그리고 HalfNetwork를 사용하면서 궁금한 점이나 버그를 발견하면
구글의 HalfNetwork 그룹스에 가입 후 글을 올려주시면 가장 빨리 답변을 얻을 수 있습니다.
http://groups.google.co.kr/group/halfnetwork?hl=ko
댓글