이번 챕터는 Windows 전용 챕터라고 할 수 있다. Winsock의 기능을 100% 활용한 라이브러리 제작에 대한 설명이기 때문이다. 즉, IOCP를 통한 프로액터(Proactor) 패턴의 비동기 I/O를 적극 활용하므로, 리눅스에서는 쓸 수 없는 라이브러리이다. 

뭐, IOCP가 리눅스의 epoll보다 성능에서 조금 더 낫고, CPU 사용량도 적으니, MMORPG같이 실시간성이 더 필요한 게임이라면 IOCP를 이용하는 것이 좋으므로, 아예 linux를 고려 안하는 것도 좋은 방법인 것 같다.

어쨌든, Winsock은 그 것 만으로도 내용이 많기 때문에 자세한 리뷰보다는 러프하게 훑고 넘어가야 할 것 같다. 



1. Network 클래스

  Network Session 하나에 대한 관리(연결/해제/송신/수신)를 담당하는 클래스로 TCP와 UDP를 모두 지원하고, select와 비슷한 EventSelect와 IOCP도 둘 다 지원한다.

  TCP는 AcceptEx,  WSASend, WSARecv가 IOCP를 위한 핵심이다. 이 책에는 클라이언트를 위한 함수에서 ConnectEx를 쓰지 않았는데, ConnectEx도 다뤄줬으면 하는 아쉬움이 있다. EventSelect 역시 지원하는데, 이 섹션에는 내용이 없고 뒤에 나오기 때문에 뒷 절의 내용을 좀 파악해야 한다.

  UDP는 Reliable UDP(RUDP)만 지원하는데, 아무래도 UDP로 게임 서버를 만들려면 패킷 유실에 대비해야 할텐데, 결국 RUDP 형태로 밖에 제작할 수 없을 것 같다. 그런데, RUDP로 통신을 할 경우, TCP보다 성능이 더 떨어지기 때문에 게임 서버는 굳이 UDP 자체를 이용할 필요가 없을 거란 생각이 든다.



2. PacketSession 클래스

  NetworkSession 클래스를 통해 수신된 데이터는 TCP의 경우에는 그냥 스트림, UDP의 경우에는 하나의 PDU로써 그 자체로는 아무런 의미를 가지고 있지 않다. 그러므로, 스트림을 모으거나(혹은 자르거나), PDU를 합치거나 하는 작업을 통해, 특정한 규칙과 의미를 가지는 메시지로 만드는 작업이 필요한데, 그 역할을 바로 이 PacketSession 클래스가 수행한다. (사견으로... packet이란 용어는 의미가 부여되지 않은 데이터 단위를 나타내므로 MessageSession... 등이 좀 더 명확하다 하겠다.)

  그런데, 수신 데이터가 모여 의미 있는 메시지가 되려면, 보낼 때부터 약속된 형식으로 데이터를 보내야 한다. 그렇기 때문에 PacketSession 클래스는 송/수신을 모두 관장하게 된다.

  PacketSession은 데이터 I/O를 위해 NetworkSession을 상속 받으며, 자신은 상위의 개념으로 동작하는 형태로 구현되어 있고, TCP/UDP를 모두 지원하기 위해 클래스 내에서 별도로 구현되어 있다.



3. EventSelect 클래스

  select 방식을 지원하기 위해 EventSelect 클래스가 따로 준비되어 있는데, 깔끔한 구조를 위해 NetworkSession에서 분리한 것으로 보인다. 즉, Application에서 NetworkSession에서 생성한 소켓을 EventSelect 인스턴스에 연결하여 주고, EventSelect에서 발생한 event에 대응하여 NetworkSession를 통해 데이터를 송수신하도록 하면 아주 깔끔한 구조로 구현이 가능한 것 같다.  

  소스 코드 자체는 복잡한 내용은 없고, WSAEventSelect()를 래핑하고, 이벤트가 발생하면 상위에 잘 통지해 주는 역할을 하고 있다. 첨언하자면, BSD의 select()와는 다르게 windows event를 이용한다는 점이 중요한 차이점이라 하겠다.



4. Iocp 클래스

  앞절의 EventSelect 클래스와 대척점에 있는 클래스이다. EventSelect는 windows event를 받는 반면 Iocp 클래스는 overlapped 즉, IOCP Queue로부터 event를 받는다. 디자인 패턴으로 생각하면 EventSelect는 리액터 패턴(reactor pattern)이라 할 수 있고, Iocp는 프로액터 패턴(proactor pattern)이라 할 수 있다.

  어쨌든, 이렇게 데이터 송수신과 event 핸들링 부분을 분리하니, 아래 단은 그대로 이용하면서 EventSelect와 Iocp를 입맛에 맞게 쓸 수 있으니 훌륭한 SW 구조를 만들 수 있게 되었다. 저자의 내공을 다시 한 번 엿볼 수 있는 대목이다.


 

Posted by JMAN