달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

IOCP란?

실제 서버에서 사용하는 소켓 IO 관리 기법. 소켓 뿐 아니라 일반 파일에도 적용 가능. 

IO가 발생하는 것을 WorkerThread들이 감지하여 처리하는 방식. 한 스레드가 작업을 처리하는 동안 다른 작업도 처리하기 위해 WorkerThread들은 ThreadPool이라는 기법을 통해 제작됨.

이벤트 방식은 초당 64개 이상의 처리를 하기 힘들고, 하나의 메시지 처리 시에 많은 리소스 소모.

IOCP는 입/출력 핸들이 작업을 시켜놓으면 IOCP가 나중에 결과를 알려주는 비동기 처리 방식.

즉, 메인 프로세스는 입/출력 진행 과정을 알 필요 없이, 해당 작업의 결과만을 통보받는다는 의미.


완료된 작업의 종류를 구분하기 위해, IOCP 등록 시 DWORD형의 Completion Key를 같이 등록.

Queue에 완료된 작업들의 결과를 저장하여 처리하고, 이 Queue를 검사하는 것이 WorkerThread의 역할이다.


CIOCP() - 생성자.

mIOCPHandle    : IOCP 관리 핸들 값. 기본 IOCP 생성 및 소켓 핸들의 IOCP 등록에 사용.

mWorkerThreadCount    : 사용할 WorkerThread 개수.

 mStartupEventHandle    : 시작 관리 이벤트

Begin() - IOCP 사용을 위한 기본 준비. 

- GetSystemInfo()    : 시스템의 정보를 가져오는 함수. SYSTEM_INFO 형식의 변수를 파라미터로 받아서 해당 변수에 시스템의 여러 정보를 멤버로 갖는 구조체를 담는다. 이 중 CPU의 정보를 이용하여 대개 CPU의 2배 만큼의 WorkerThread를 생성한다.


- CreateIoCompletionPort()    : IOCP 핸들 생성 함수. 


- CreateEvent()     : 시작 관리 이벤트 생성. 



- mWorkerThreadVector    : 생성한 WorkerThread들을 관리하는 벡터. for문을 이용하여 CreateThread()로 WorkerThread 생성 후 리턴값으로 받은 해당 스레드의 핸들 값을 push_back()을 통해 벡터에 넣어주고 WaitForSingleObect를 통해 스레드가 완전히 생성될때까지 대기한다.(아니면 WaitForSingleObject에 파라미터로 받는 mStartupEventHandle에 이벤트가 발생할때까지 대기?)

     Q. WaitForSingleObject가 정확히 어떨때 어떤 역할을 하는지?



End() - 생성해둔 WorkerThread를 종료하고, mIocpHandle을 초기화하여 WorkerThread들을 관리하던 Vector를 초기화해줌. 

- PostQueuedCompletionStatus()    : 첫번째 파라미터로 받는 IOCP 핸들에 강제적으로 신호를 발생시키는 함수. 2~4번째 파라미터로 받는 데이터를 신호에 담아 그대로 WorkerThread에 보낸다.



RegisterSocketToIocp() - 소켓/파일 핸들을 IOCP에 등록하는 함수. 소켓이나 파일을 등록해두지 않으면 WSARecv, WSASend를 아무리 호출해도 IOCP에서 신호를 찾을 수 없음.

- 이 함수 내에서 이루어지는 CreateIoCompletionPort()함수의 파라미터는 소켓 핸들, 메인 IOCP 핸들, Completion Key등을 넣어주고, 이 리턴값을 다시 메인 IOCP핸들에 덮어쓴다. 이 과정을 통해서 소켓/파일 핸들이 IOCP에 등록된다.

Q. 왜 처음에 기본 IOCP핸들을 선언해주고 다시 메인 핸들에 덮어쓰는지?



WorkerThreadCallback() - GetQueuedCompletionStatus()함수를 통해 받은 파라미터의 모든 것을 판단하고 처리. 

- 어떠한 IO가 발생했을 때 항상 Overlapped가 넘어오게 된다. 윈도우OS 레벨에서 Overlapped 구조체를 메모리에 계속 유지하면서, IO가 발생했을 때 해당 이벤트와 짝지어 넘겨주기 때문에 이를 통해 넘어온 이벤트의 종류를 알 수 있음.


- NetworkSession 클래스에서 Accept, Read, Write 각각에 대한 Overlapped를 만들어두고 그에 대한 IoType을 해당 작업에 맞는 것으로 설정해 둠으로써 어떤 작업의 IO인지를 알 수 있음.


- Overlapped_Ex->Object 필드는 신호를 보낸 접속자를 구분하기 위해 만든 필드. 하나의 접속자마다 NetworkSession 클래스가 1개씩 할당되는데, 이 NetworkSession클래스가 초기화될 때 위에서 언급한 Accept, Read, Write에 대한 각각의 Overlapped클래스의 Object에 this를 넣어줌으로써 어떤 접속자가 보낸 것인지 구분할 수 있다.



- GetQueuedCompletionStatus()    : 대기하다가 큐에서 신호를 가져오는 함수. 입력 파라미터로 사용할 IOCP 핸들 값과 대기 시간을 받고, 출력 파라미터로 발생한 IO의 데이터 크기, 키 값, Overlapped 값을 WorkerThreadCallback() 시작 시 선언한 세 변수에 저장한다. 

이 함수를 통해 받은 값들을 분석하여 각각의 IO 형태에 맞는 가상함수들을 처리해준다.








:
Posted by 웽웽