2011년 2월 23일 수요일

블로킹 소켓 VS 넌블로킹 소켓

■ 소켓모드

소켓은 소켓 함수 호출시 동작 방식에 따라 블로킹과 넌블로킹 소켓으로 구분하며 이를 소켓모드라고 부른다.

○ 블로킹 소켓
소켓 함수 호출 시 조건이 만족되지 않으면 함수는 리턴하지 않고 해당 스레드는 대기 상태가 된다.
소켓 함수는 리턴하지 않으므로 멀티스레드를 사용하여 다른 작업을 하지 않는 한 애플리케이션이 더는 진행할 수 없다.
socket() 함수는 기본적으로 블로킹 소켓이다.

○ 넌블로킹 소켓
소켓 함수 호출 시 조건이 만족되지 않더라도 함수가 리턴하므로 해당 스레드는 계속 진행 할 수 있다.
ioctlsocket()함수를 호출해야만 넌블로킹 소켓으로 바꿀 수 있다.

SOCKET  listen_sock = socket( AF_INET, SOCK_STREAM, 0 );

u_long on = TRUE;
retval = ioctlsocket( listen_sock, FIONBIO, &on );

넌블로킹 소켓은 WSAGetLastError()함수를 호출하여 반드시 오류코드를 확인해야 한다.
WSAEWOULDBLOCK() -> 넌블로킹 소켓을 사용할 경우의 오류 코드.
이는 만족하지 않고 넘어간 것이므로 나중에 다시 소켓 함수를 호출하면 된다.

client_sock = accept( listen_sock, ( SOCKADDR* )&clientaddr, &addrlen );
if( client_sock == INVALID_SOCKET )
{
        if( WSAGetLastError() != WSAEWOULDBLOCK )
        {
                 //   에러 처리
        }
        continue;
}

넌블로킹 소켓에서는 다음과 같이 WSAEWOULDBLOCK를 항시 체크하여 다시 소켓함수를 호출하여야 한다.
※ listen_sock가 넌블로킹이면 client_sock도 넌블로킹 소켓이 된다.


■ 넌블로킹 소켓의 특징

장점 : 소켓 함수 호출 시 블록되지 않으므로 다른 작업을 진행 할 수 있다.
         멀티스레드를 사용하지 않고 여러 개의 입출력을 처리 할 수 있다.

단점 : 소켓 함수를 호출할 때마다 WSAEWOULDBLOCK등 오류 코드를 확인하고,
         다시 해당 함수를 호출해야하므로 프로그램 구조가 복잡해진다.
         블로킹 소켓을 사용한 경우보다 CPU사용률이 높다.


■ 이상적인 소켓 입출력 모델

1. 모든 Client가 접속이 성공한다.
2. Server는 각 Client의 서비스 요청에 최대한 빠르게 반응하며 고속으로 데이터를 전송한다.
3. 위와 같은 기능을 제공하되 시스템 자원 사용량을 최소화한다. 즉 CPU 사용률이나 메모리 사용량등을 최소화한다.


■ 소켓 입출력 모델에 요구되는 사항

1. 소켓 함수 호출 시 블로킹을 최소화 한다.
    CPU사용률을 최소한으로 하면서 넌블로킹 소켓을 사용한 모든 소켓 함수 호출을 성공시켜야 한다.

2. 입출력 작업을 다른 작업과 병행한다.
   
3. Thread 개수를 최소화한다.
    Thread를 생성할 때마다 1MB의 메모리가 할당된다.
    시스템 내의 Thread 수가 많아질수록 각 Thread의 응답속도는 느려지므로 결과적으로 Server의 성능 저하를 불러온다.
    -> Context switching이 자주 발생하므로 늦어진다.

4. 유저모드와 커널모드 전환 횟수와 데이터 복사를 최소화 한다.
    유저모드와 커널모드의 전환은 상당한 CPU 사이클을 소모한다. 

댓글 없음:

댓글 쓰기