Completion Port의 생성

Posted 2012. 8. 13. 22:48

IOCP에선 완료된 IO의 정보가 Completion Port 오브젝트(이하 CP 오브젝트)라는 커널 오브젝트에 등록된다.

" 이 소켓을 기반으로 진행되는 IO의 완료상황은 저 CP오브젝트에 등록해 주세요 " 라는 요청의과정이 선행되어야 한다.

이를 가리켜 소켓과 CP오브젝트와의 연결 요청 이라 한다.

때문에 IOCP 모델의 서버 구현을 위해서는 다음 두 가지 일을진행해야 한다

1.Completion Port 오브젝트의 생성

2.Completion Port 오브젝트와 소켓의 연결

이떄 소켓은 반드시 Overlapped 속성이 부여된 소켓이여야 함.

 

생성과 연결 함수

HANDLE CreateIoCompletionPort(

HANDLE FileHandle,

HANDLE ExistingCompletionPort,

ULONG_PTR CompletionKey,

DWORD NumberOfConcurrentThreads

);

-> 성공시 CP 오브젝트의 핸들, 실패시 NULL 반환

지금은 생성이니까 생성시점으로 설명)

  1. 입출력 완료 포트를 새로 생성하고
  2. 소켓과 입출력 완료 포트를 연결한다. 연결하면 이 소켓에 비동기 입출력 결과가 입출력 완료 포트에 저장된다.

 

FileHandle : 새로운 입출력 완료포트를 생성할때는 INVALID_HANDLE_VALUE를 전달

ExistingCompletionPort : 파일 또는 소켓과 연결할 입출력 완료 포트 핸들. 새로운입출력 완료 포트를 생성할땐 NULL 전달

CompletionKey : 입출력 완료 패킷에 들어갈 부가적인 정보를 32비트 값을 줄수있다. 생성시는 0을 전달

NumberOfConcurrentThreads : 동시에 실행할수있는 작업자 스레드의 개수. 0을 사용하면 자동으로 CPU개수와 같은수로 설정.

                                         최대설정수는 2.

 

ex) HANDLE hCpObject;

......

hCpObject = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 2 );

 

SOCKET sock;

HANDLE hResult = CreateIoCompletionPort( ( HANDL)sock, (DWORD)sock, 0 );

 

 

결론은 생성할땐 생성옵션에 맞춰서 함수를 호출하고 연결할땐 연결옵션에 맞춰서 함수를 호출.

 

즉.. 만들때 한번호출하고.. 이미 있는걸 연결할때 또 호출하고..

 

 

 

 

 

 

 

'Server > IOCP' 카테고리의 다른 글

GetQueuedCompletionStatus() 함수  (0) 2012.08.13
Completion Port 오브젝트와 소켓의 연결  (0) 2012.08.13
IOCP  (0) 2012.08.13

IOCP

Posted 2012. 8. 13. 22:48

Completion Port모델은 모든 소켓 입출력 모델 중 가장 뛰어난 성능을 제공한다.

보통 입출력 완료포트( I/O Completion Port ) 를 줄여서 IOCP라 칭한다.

 

입출력 완료포트는 비동기 입출력 결과와 이 결과를 처리할 스레드에 대한 정보를 담고 있는 구조로 APC큐와 비슷한 개념이다.

APC : 비동기 함수를 호출하는 매커니즘

 

APC와 IOCP의 차이점

1, 생성과 파괴

-> APC큐는 각 스레드마다 자동으로 생성되고 파괴된다.

-> IOCP는 CreateIoCompletionPort() 함수를 호출하여 생성하고 CloseHandle() 함수를 호출하여 파괴한다.

 

2. 접근 제약

->APC큐는 저장된 결과는 APC큐를 소유한 스레드만 확인할수 있지만 IOCP에는 이런 제약이 없다.

-> 보통 입출력 완료 포트를 접근하는 스레드를 별도로 두는데 이를 작업스레드라 한다.

 

3.  비동기 입출력 처리 방법  

->APC큐는 저장된 결과를 처리하려면 해당 스레드는 alertable wait 상태에 진입해야 한다.

-> IOCP에 저장된 결과를 처리하려면 작업자 스레그는 GetQueuedCompletionStatus() 함수를 호출해야 한다.

 

IOCP 소켓 입출력 절자

  1. CreateIocompletionPort() 함수를 호출하여 입출력 완료 포트를 생성
  2. CPU 개수에 비례하여 작업자 스레드를 생성

    모든 작업자 스레드는 GetQueuedCompletionStatus() 함수를 호출하여 대기 상태가 된다.

  3. 비동기 입출력을 지원하는 소켓을 생성한다.

    이 소켓에 대한 비동기 입출력 결과가 입출력 완료 포트에 저장되려면

    CreateIoCompletionPort() 함수를 호출하여 소켓과 입출력 완료 포트를 연결해야 한다.

  4. 비동기 입출력 함수를 호출한다.

    비동기 입출력 작업이 곧바로 완료되지 않으면 소켓 함수는 오류를 리턴하고 오류코드는 WSA_IO_PENDING으로 설정된다.

  5. 비동기 입출력 작업이 완료되면 운영체제는 입출력 완료 포트에 결과를 저장하고

    대기 중인 스레드 하나를 깨운다.

    대기 상태에서 깨어난 작업자 스레드는 비동기 입출력 결과를 처리한다.

  6. 새로운 소켓을 생성하면 3~5를.. 그렇지 않으면 4~5를 반복한다.

 

 

여기서 ...

IOCP에서는 IO를 전담하는 쓰레드를 별도로 생성하고 이 쓰레드가 모든 클라이언트를 대상으로 IO를 진행하게 됨.

입출력 함수인 WSASend, WSARecv 함수를 호출하는 쓰레드는 우리가 직접 생성해야 한다.

다만 이 쓰레드가 입출력의 완료를 위해 GetQueuedCompletionStatus함수를 호출할뿐이다.

그리고 GetQueue....함수는 어떤 스레드든 호출 가능하지만 실제 IO의 완료에 대한 응답을 받는 쓰레드의 수는 

CreateIoCompletionPort호출시 지정한 최대 쓰레드의 수를 넘지않는다.

 

적정수는 CPU에 존재하는 코어의 수로 이해하는것이 좋다.

 

워커쓰레드의 갯수가 cpu*2인 이유. MS의 표준임..

 

즉 IOCP란

Input Ouput Completion Port즉 인풋 아웃풋 작업이 완료 되었을때 포트를 통해서 일을 처리하는것을 말한다.

그 일이 워커쓰레드 에서 한다.

 

동기식 : send나 recv함수가 완료되기 전에는 실행 코드가 움직이지 않는다

비동기식 : send나 recv는 우선 운영체제에게 소켓 작업을 한다고 알려죽 ㅗ후에 완료 통지를 받는 방식이다.

중첩소켓 : 여러개의 소켓 입출력 작업이 운영체제로 들어가면 몇개는 입출력 시간이 겹쳐도 작업이 가능하다는 매우 획기적인 기술

               중첩되는 시간만큼 속도가 빨라진다는 장점을 가직 ㅗ있다.

 

비동기 I/O가 완료되면 정보단위가 만들어지고 이것이 IOCP큐에 들어간다. 이때 작업 스레드는 IOCP의 통지를 받고 IOCP큐에서 정보 단위 하나를 가져와

작업을 수행하게 된다.

IOCP는 하나의 스레드가 하나 이상의 사용자로부터의 요구를 처리 할 수 있도록 해준다. 꼭 한개의 스레드를 사용하는 건 아니다.

상황에 맞게 스레드의 개수를 조절 할 수 있다.

작업 스레드가 많으면 좋지만. 스레드가 많아지게 되면 context switching이 많이 일어 나므로 적은 수으 ㅣ스레드를 사용.

context switching은 윈도우 2000, nt 이상에서 지원해준다( 자동으로 해줌..)

IOCP의 가장 큰 장점은 쓰레드 풀을 통한 context switching 비용이 줄어든다. 

 

'Server > IOCP' 카테고리의 다른 글

GetQueuedCompletionStatus() 함수  (0) 2012.08.13
Completion Port 오브젝트와 소켓의 연결  (0) 2012.08.13
Completion Port의 생성  (0) 2012.08.13

기본 함수 20개

Posted 2012. 8. 13. 22:47

기본 20개의 함수들을

보충해주기위해

나머지들이 도와주는..( 쓰레드, 동기화 등등 )

함수들을. 클래스화로 ..

그리고 함수들의 인자들 확실히. 알고넘기기

 

2) 소켓 초기화 socket

3) bind()

4) listen()

5) accept()

6)recv()

7)sand()

8)closesocket()

10)함수호출시 오류코드()

11)sin_family

12)sin_port

13)sin_addr

14)바이트 정렬 함수 htons : s 쇼트. 짧은거 port에 사용   -> 호스트 바이트 순에서 네트워크 바이트 순으로 변경 : 네트워크방식 -> 빅 엔디엔

15)바이트 정렬 함수 htonl : l 롱. 긴거 ip에 사용

ntohs : 네트워크 순에서 호스트순 쇼트로( PORT )

ntohl : 네트워크 순에서 호스트 순으로 롱으로( IP )

빅 엔디엔 : 상위 바이트의 값을 작은 번지수에 저장하는 방식

리틀 엔디엔 : 상위 바이트의 값을 큰 번지수에 저장하는 방식

컴퓨터 저장방식은 두가지 방식이 있음. 빅 엔디엔 방식과 리틀 엔디엔 방식.

빅 엔디엔 방식의 0x12, 0x24, 0x36 방식으로 저장되는걸 리틀엔디엔에서는 0x36, 0x24, 0x12 순으로 전송

네트워크상에서 통일 시켜주지않으면 뒤죽박죽..

 

16) IP주소 변환 함수 inet_addr

inet_addr : 32비트 정수형태로 IP주소를 변환

inet_ntoa : 인자로 전달된 정수형태의 IP정보를 참조하여 문자열 형태의IP정보로 변환해서 변환된문자열의 주소값을 반환함. 반환형이 char형임

             : 임시공간에 이미 저장시켜버림. 다음에 호출되면 이전께 지워지니까. 필요에따라선 따로 저장해둬야됨.

inet_aton : 문자열 형태의 IP주소를 32비트 정수, 그것도 네트워크 바이트 순서로 정렬해서 반환함. 다만 구조체변수 in_addr를 이용하는형태.

 

 

17) 도메인이름->ip주소 함수 getthostbyname

18) ip주소->도메인이름 함수 gethostbyaddr

19)클라의 connect

20) udp의 sendto, recvfrom

21) select 함수( 스레드없이 유저수64 이하의 데이터를 동시 컨트롤할수있음 )

 

21) TCP / UDP

22) 멀티캐스트 / 브로드캐스트

 

23) IP 주소 변환 함수

inet-addr()함수는 문자열 형태로 IP주소를 입력받아 32비트 숫자( 네트워크 바이트 정렬)로 리턴한다.

inet_ntoa()함수는 32비트 숮자(네크워크바이트 정렬)로 IP주소를 입력받아 문자열 형태로 리턴한다.

 

그 다음 쓰레드, 동기화

스레드 없이 동시컨트롤이. select, 비동기화 select, event select 3가지뿐.

« PREV : 1 : ··· : 62 : 63 : 64 : 65 : 66 : 67 : 68 : ··· : 77 : NEXT »