개요
AcceptEx()을 사용해서 비동기 접속을 진행할 수 있다는 점을 제외하면 기존 동기 함수인 accept()와 차이를 느끼기는 어렵다. AcceptEx()는 accept()와 다르게 미리 소켓을 생성해야 한다. 그렇다면 왜 MS는 accpet()처럼 자식 소켈을 반환해주는 게 아닌 미리 만들어진 소켓을 요구했을까? 그 이유는 이 API의 핵심이 "소켓을 재사용할 수 있다"는 것이다.
소켓을 생성하고 닫는 과정은 적지 않은 오버헤드를 유발한다. 소켓은 ISO 7 레이어에 기반하고 있다.
그래서 커널 영역에는 전송 계층(Layer4) 부터 시작하여 IP 계층인(Layer 3) 링크 계층인(Layer 2)로 이어지는 여러 계층의 구현이 존재하며 소켓을 생성하거나 해제할 경우 그 요구에 맞추어 레이어별 작업이 이루어져야 하기 때문에 소켓 커널 객체 자체의 생성과 해제가 적지 않은 시스템 부하와 자원을 요구하는 것이다.(윈도 시스템 프로그램을 구현하는 기술)
이러한 소켓 재사용을 진행하기 위해서는 MS에서 제공하는 또 다른 API가 필요하다 바로 DisconnectEx() 함수이다.
이 함수는 AcceptEx()와 다르게 함수가 없으며 ConnetEx()와 동일하게 함수 포인터를 이용해서 가져와야 한다.
다음은 DisconnectEx() 함수의 원형이다.
프로젝트 정보(Project Informaion)
사진 및 프로젝트 설명
프로젝트는 Server, Clinet 이렇게 두 개의 프로젝트가 있다.
Server: Server.cpp, Server.h
Clinet: Iocp_CIocp_Client.cpp, Server.h(Server의 헤더 파일을 공유한다.)
최대 접속 클라이언트와 소켓은 3명까지 이며 그 이후는 서버에서 받지 않는다.
처음 서버를 시작하면 사전에 정의해놓은 Socket 만큼 Init을 진행하며 해당 내용을 출력한다.
처음 서버를 가동하면 AcceptEx()에서 미리 정의해놓은 소켓만큼 호출하고 또 IOCP에 등록을 진행한다.
여기서 OVER_EX 구조체를 동적 할당으로 일일이 주지 않으면 소켓이 겹치는 현상이 생겨서 하나하나 동적을 할당을
통해 진행을 하였다.
- 이 OVER_EX를 IO가 끝나면 지워야 하는지 궁금하고 해결하지 못했다..(일단 지우지 않고 진행을 하였다.)
클라이언트에서 접속을 시도할 때마다 Accpet 한 소켓이 나오며 클라이언트를 제거할 때마다 해당 소켓이 Disconnect
됐다는 통지를 볼 수 있다.
(Disconnect 통지가 느린데 이유는 잘 모르겠다. Disconnect를 동기 함수로 처리했을 때에는 문제가 없었지만 비동기 처리를 하니 이러한 오류가 발생했다.)
4번째 클라이언트가 접속을 시도하면 서버에서는 소켓수보다 많기 때문에 접속을 받지 않으며 기존 클라이언트가 서버에서 나가면 새로 접속을 시도하는 클라이언트가 접속이 되는 것을 볼 수 있다.( 물론 여기서도 버그가 있다..)
후기
소켓 풀을 IOCP에 적용해서 구현을 진행해보았다.. 사실 보이는 버그도 많았고 찾지 못한 버그도 있기 때문에 만족하지 못하는 프로젝트이다. 재사용을 해보았다 는 거에 의의만 두고 있다
이 프로젝트를 하면서 느낀 점은
1. 진행하면서 발생하는 오류가 왜 발상하는지 알기 어렵고 이렇게 하는 게 맞는지 의문이 들다 보니 처음으로 누가 알려줬으면 좋겠다는 생각이 들었다. 하루빨리 취업이나 학원을 통해 해결하고 싶다.
2. 뭐든지 해제가 어려운 거 같다. 여기선 CloseSocket을 진행하지 않고 재사용하지만 CloseSocket을 진행할 때에도 바로 지우는 게 아닌 IO큐가 다 끝났는지 확인 후 지워야 한다고 한다. IOCP에 대해서 좀 더 공부가 필요하다고 느꼈다.
3. 서버 코드가 너무 지저분하다 보니 나도 나만의 소켓 라이브러리를 통해 재사용 가능한 코드를 만들고 싶다고 생각했고 이러한 라이브러리 제작을 통해 공부를 진행해볼 예정이다.
유의사항
* 현재 Disconnect 로그가 가끔 안 나오거든 Disconnnect 관련 버그가 있습니다.
* Clinet는 Server의 헤더 파일을 공유합니다.
* 기본 루프 백(127. 0. 0. 1)과 PORT(9000)이며 네트워크를 통한 테스트는 진행하지 않았습니다.
* TCP환경에서 발생할 수 있는 패킷 수신은 고려하지 않고 진행했습니다.
* 만약 이 블로그 글을 보고 잘못된 점이나 참고 가능한 것 등 공부가 가능한 게 있다면 댓글이나
메일(SnowFleur0128@gmail.com)로 보내주시면 감사하겠습니다.
출처 및 소스코드 링크
DisconnectEx: docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms737757(v=vs.85)
git: github.com/SnowFleur/2020-Server/tree/master/IOCP-SocketPool%2CDisConnectEx
관련 글
[게임 서버(Game Server)] - [게임 서버] AcceptEx와 ConnectEx-IOCP
[게임 서버(Game Server)] - [게임 서버] AcceptEx와 ConnectEx
'게임서버(Game Server)' 카테고리의 다른 글
[게임서버] IOCP Page-Locking (0) | 2020.12.05 |
---|---|
[게임서버] OSI 7계층 및 3-way, 4-way (0) | 2020.08.19 |
[게임서버] AcceptEx와 ConnectEx-IOCP (1) | 2020.05.14 |
[게임서버] AcceptEx와 ConnectEx (0) | 2020.05.13 |
[게임서버] 유니티(C#)에서 Pragma pack 사용법 (0) | 2020.04.12 |