5.1 윈속의 이해
▶ 윈속은 마이크로소프트(Microsoft) 윈도우3.1 또는 윈도우95에서 제공하는 TCP/IP 프로그래밍을 위한 API(Appli- cation Program Interface)로서 사용방법 및 기본 동작이 UNIX의 BSD 소켓과 거의 같으며 BSD 소켓과 마찬가지로 클라이언트-서버 모델을 기초로 하여 이용된다.
5.1.1 UNIX BSD 소켓과 윈속의 차이
▶ 윈속의 사용방법과 문법이 BSD 소켓의 경우와 유사하기는 하지만 윈속과 BSD 소켓용으로 작성된 프로그램은 서로 호환성이 없으며 이 두 가지 소켓 응용 프로그램이 호환성을 갖으려면 많은 부분을 수정하여야 한다.
▶ 먼저 윈도우와 UNIX 운영체제의 차이점을 비교하면 다음과 같다.
▶ 첫째, UNIX와 달리 윈도우3.1 이하에서는 멀티태스킹을 지원하지 않는다.
▶ 윈도우95는 멀티태스킹과 유사한 멀티쓰레드(multi- thread)를 지원하기는 하지만 윈속이 처음 소개된 것은 멀티태스킹이 지원되지 않는 윈도우3.1에서였으며 윈도우95와 윈도우3.1에서의 프로그램 호환성을 유지하기 위하여 윈속은 윈도우95에서도 계속 '멀티태스킹이 지원되지 않는' 환경을 가정하고 있다.
▶ 이와같이 UNIX와 윈도우 운영체제의 기본적인 차이로 인하여 윈속은 BSD 소켓과 내부적으로 매우 다른 특성을 갖고 있으며 프로그램 작성시에도 이를 고려하여야 한다.
▶ 둘째로 윈속은 주로 윈도우 프로그래밍으로 구현되는데, 윈도우 프로그래밍이 '메시지 구동형 프로그래밍'이라는 것이 UNIX 프로그램과 크게 다른 점이다.
▶ 메시지는 '어떤 사건(event)의 발생을 알리는 신호'라고 할 수 있는데, 메시지는 사용자가 만든 응용 윈도우들이 서로 주고받거나, 윈도우 운영체제가 사용자 윈도우에게 전달하는 것이다.
▶ 한편 윈속 프로그래밍에서는 윈속의 기능을 제공하는 라이브러리로 DLL(Dynamic Link Library)인 Winsock.dll을 사용한다.
▶ 이러한 DLL 라이브러리는 컴파일시 링크되는 것이 아니라 응용 프로그램 수행시 링크된다.
▶ DLL을 사용하는 것의 장점은 여러 응용 프로그램이 하나의 DLL을 공유하여 사용할 수 있다는 것이다.
▶ 예를들면 하나의 Winsock.dll이 수행중이면 여러 윈속 응용 프로그램들이 이것을 동시에 사용할 수 있게 된다.
▶이외에도 BSD 소켓과 윈속은 소켓을 열고 닫는 데 쓰이는 함수가 다른데 윈속의 경우 WSAStartup(), WSACleanup()함수를 통해 소켓과 Winsock.dll과의 관계를 설정, 해제해 주는 과정이 필요하다.
▶ BSD 소켓처럼 close()를 이용해 소켓을 닫는 것이 아니라 closesocket() 함수를 사용해 닫아야 한다.
▶ 이와같은 차이는 UNIX와 윈도우 운영체제의 특성의 차이로 인한 것이며 함수의 이름만 다른 것이 아니라 함수의 구체적인 내부 동작도 서로 다르다.
5.1.2 윈속의 동작모드
▶ BSD 소켓과 마찬가지로 윈속이 제공하는 소켓도 다음과 같은 세 가지 동작모드 (operating mode)를 가지고 있다.
- Blocking 모드
- Non-blocking 모드
- Asynchronous(비동기) 모드
(1) Blocking 모드
▶ socket() 시스템 콜을 호출하여 하나의 소켓을 만들면 이것은 디폴트로 blocking 모드로 동작하는 소켓이 된다.
▶ 이러한 blocking 모드의 소켓을 대상으로 accept(), close- socket(), connect(), recv(), recvfrom(), send(), sendto()와 같은 함수를 호출하면 함수가 원하는 동작을 완료할 때까지 함수를 호출한 프로세스가 blocking될 수 있다.
▶ 즉, blocking 모드의 소켓에서는 응용 프로그램에서 위와같은 함수를 호출하였을 때 그 동작이 완료되어 함수가 리턴되어야 다음 작업을 할 수 있게 된다.
▶ 한편 멀티태스킹이 지원되는 UNIX 컴퓨터에서는 block- ing 모드의 소켓을 사용하여 어떤 응용 프로그램이 블록되어도 컴퓨터 전체 동작에는 큰 문제가 되지 않는다.
▶ 왜냐하면 멀티태스킹 운영체제에서는 각각의 프로세스들이 독립적으로 수행되므로 한 프로세스가 블록되어 있어도 다른 프로세스들은 계속 수행될 수 있기 때문이다.
▶ 그러나 윈도우3.1과 같은 단일 태스킹 운영체제에서는 프로그램이 한 곳에 블록되어 있으면 PC 전체가 블록될 수 있다.
▶ 또한 blocking 모드의 소켓을 사용하면 하나의 프로그램에서 여러 개의 소켓을 동시에 개설하여 각각의 입출력을 처리하는 형태의 응용 프로그램을 작성하기가 어렵다.
▶ 따라서 윈속 프로그래밍에서는 이를 해결하기 위하여 소켓을 non-blocking 모드 또는 비동기 모드로 변경하여 사용하는 것이 필요하다.
(2) Non-blocking 모드
▶ Non-blocking 모드 소켓이란 accept(), closesocket(), connect(), recv(), recvfrom(), send(), sendto()와 같은 함수가 호출되었을 때 함수의 원하는 동작이 완료되는 것과 무관하게 일단 함수가 즉시 리턴되는 소켓을 말한다.
▶ 소켓이 처음 만들어지면 디폴트로 blocking 모드가 되는데 프로그래머는 필요에 따라 blocking 모드의 소켓을 non-blocking 모드로 바꿀 수 있다.
▶ Non-blocking 모드의 소켓을 사용하는 이유는 응용 프로그램이 이곳에서 멈추어 있지(block) 않게 하기 위해서이다.
▶ Non-blcoking 모드의 소켓에서 함수 호출이 즉시 리턴되었을 때 그 결과는 다음과 같이 두 가지로 종류로 나눌 수 있다.
1) 성공적인 리턴: 함수의 동작이 즉시 성공적으로 수행되었음.
2) 에러 리턴: 함수 수행중 에러가 발생했거나 함수가 블록되었음.
▶ 즉, non-blocking 모드 소켓에서 즉시 리턴된 함수 호출 결과는 성공적인 경우도 있고 실패한 경우도 있을 수 있다.
▶ 에러 리턴인 경우 에러코드가 WSAEWOULDBLOCK이면, 이것의 의미는 함수의 동작이 잘못되었다는 것이 아니라 '이 함수가 동작 완료될 때까지 기다린다면 block될 수 있다'는 것을 의미한다.
▶ 이와같이 에러코드가 WSAEWOULDBLOCK인 경우 그 원인은 다음의 두 가지 중 하나가 된다.
1) Winsock.dll이 함수가 원하는 동작을 시작했으나 아직 종료되지 않았음.
2) 함수의 동작이 시작되지 못했으며 다시 재시도를 필요로 함.
▶ 위의 첫번째 경우는 응용 프로그램이 함수의 동작 완료 시점을 알아서 그 결과를 처리하여야 하며 두번째 경우는 응용 프로그램이 이 함수가 성공적으로 시작될 때까지 함수를 계속 반복하여 호출해야 한다.
▶ 어떤 경우이든 non-blocking 모드 소켓의 처리는 다소 복잡하며 따라서 다음에 설명할 비동기 모드를 사용하는 것이 편리하다.
(3) Asynchronous(비동기) 모드
▶ 비동기 모드에서도 non-blocking 모드에서처럼 소켓 관련 함수의 호출이 바로 리턴된다.
▶ 그러나 비동기 모드에서는 non-blocking 모드와 달리, 함수의 동작이 완료되는 시점, 또는 함수의 실행이 시작되지 못한 경우 다음에 다시 재시도하여야 하는 시점을 시스템(Winsock.dll)이 메시지 처리 방식으로 나중에 응용 프로그램에게 알려준다.
▶ 즉, 비동기 모드의 소켓에서 소켓관련 함수의 실행결과의 에러코드가 WSAEWOULDBLOCK일 때의 의미는 다음과 같다.
1) 함수의 동작이 완료되면 그 때 Winsock.dll이 메시지를 통하여 동작의 완료를 알려주거나,
2) 함수의 동작이 시작하지 못했으며, 함수를 다시 호출해야 할 시점을 나중에 비동기적으로 알려주겠음.
▶ 앞에 언급한 바와 같이 UNIX와 같은 운영체제에서는 함수가 블록되는 것이 문제가 되지 않으므로 반드시 비동기 모드의 소켓을 사용할 필요는 없다.
▶ 그러나 윈속에서는 비동기 모드로 소켓을 사용하는 것이 편리하다.
(4) Blocking 함수
▶ 한편 blocking 모드의 소켓이 아니더라도 (즉, non- blocking 또는 비동기 모드의 소켓에서도) 어떤 함수들은 함수 자체의 특성상 블록될 수 있는 함수가 있다.
▶ 이러한 함수들은 네트웍 시스템(즉, TCP/IP)이 어떤 정보를 얻어내야만 그 결과를 리턴할 수 있으며 그 정보를 얻는데 다소 시간이 필요하기 때문이다.
▶예를들어 호스트의 도메인 네임을 입력하고 이 호스트의 IP 주소 등의 정보를 얻어내는 함수 gethostbyname()이 처리되기 위하여는, 네트웍 시스템이 DNS 서버에게 필요한 정보를 문의하고 그 결과가 도착할 때까지 기다려야만 한다.
▶ 이러한 함수들을 'blocking 함수'라고 부르며 표 5-1에 대표적인 blocking 함수들을 정리하였다.
함 수 | 기 능 |
select() | 소켓의 상태 변화(읽기, 쓰기, 오류 발생)를 알려줌 |
gethostbyaddr() | 호스트 주소로부터 호스트 정보를 얻음 |
gethostbyname() | 호스트 이름으로부터 호스트 정보를 얻음 |
getprotobyname() | 프로토콜 이름으로부터 프로토콜 번호를 얻음 |
getprotobynumber() | 프로토콜 번호로부터 프로토콜 이름을 얻음 |
getservbyname() | 서비스 이름으로부터 서비스 정보를 얻음 |
getservbyport() | 포트번호로부터 서비스 정보를 얻음 |
표 5-1 대표적인 blocking 함수
▶ 표 5-1에 소개한 blocking 함수들은 소켓의 동작 모드에 관계없이 항상 블록될 수 있는 함수이다
▶ 이러한 함수를 사용할 때 프로그램이 블록되는 문제를 해결하기 위하여, 윈속에서는 이들 blocking 함수와 같은 기능을 수행하면서 실제로는 비동기 모드로 동작하는 즉, 함수 실행결과를 비동기적으로 알려주는 비동기 함수들을 제공하고 있다.
▶ 이들을 표 5-2에 정리하였으며 자세한 내용은 5.2.2절에서 설명하겠다.
비동기 함수 | 기 능 |
WSAAsyncSelect() | 소켓의 I/O 상태 변화 즉, 연결요청, 데이터 수신, 송신 버퍼의 사용가능 등의 이벤트를 시스템이 메시지를 통하여 알려주도록 요청함 |
WSAAsyncGetHostByAddr() | 호스트 주소로부터 호스트 정보를 얻음 |
WSAAsyncGetHostByName() | 호스트 이름으로부터 호스트 정보를 얻음 |
WSAAsyncGetProtoByName() | 프로토콜 이름으로부터 프로토콜 번호를 얻음 |
WSAAsyncGetProtoByNumber() | 프로토콜 번호로부터 프로토콜 이름을 얻음 |
WSAAsyncGetServByName() | 서비스 이름으로부터 서비스 정보를 얻음 |
WSAAsyncGetServByPort() | 포트번호로부터 서비스 정보를 얻음 |
표 5-2 Blocking 함수(표 5-1)의 기능을 수행하는 윈속의 비동기 함수
5.1.3 윈속의 시작과 종료
(1) WSAStartup()
▶ WSAStartup()은 윈속 관련 함수들을 사용하기 전에 응용 프로그램이 반드시 호출해야 하는 함수로, 윈속 라이브러리인 Winsock.dll을 초기화한다.
▶ WSAStartup()은 일반적으로 윈도우 메시지 WM_CREATE나 WM_INITDIALOG의 처리 부분에서 호출된다.
▶ WSAStartup()은 두 개의 인자를 필요로 하는데, 응용 프로그램이 요구하는 최소의 윈속 버전(1.0 또는 1.1) 값과, WSAStartup()이 수행된 후 네트웍 시스템(Winsock.dll)이 윈속 관련 정보를 알려주는데 사용할 윈속정보 구조체, 즉 WSADATA 타입의 구조체 변수의 주소를 필요로 한다.
▶ 다음은 응용 프로그램이 사용할 윈속의 버전값을 지정하고 WSAStartup()을 호출하는 예이다.
WORD wVersionRequired ; /* 사용할 윈속 버전 값 */ WSADATA wsaData ; /* 윈속정보를 담을 구조체 */
wVersionRequired = MAKEWORD(0, 1); /* 윈속 버전 값을 1.0으로 세팅 */
WSAStartup(wVersionRequired, &wsaData); /* 윈속의 시작 */
▶ 위에서 wsaData는 WSADATA 타입의 구조체 변수로 여기에는 WSAStartup() 함수가 개설하여 앞으로 사용할 윈속에 관한 정보가 수록되어 리턴된다.
▶ WSADATA 구조체의 정의는 다음과 같다(Winsock.h 파일 참조).
typedef struct WSADATA { WORD wVersion; /* 윈속 버전 (예 1.0) */ WORD wHighVersion; /* 최상위의 윈속 버전 (예 1.1) */ char szDescription[WSADESCRIPTION_LEN+1]; /* 회사정보 */ char szSystemStatus[WSASYS_STATUS_LEN+1]; /* 구성정보 */ unsigned short iMaxSockets; /* 한 프로세스가 열 수 있는 소켓 수 */ unsigned short iMaxUdpDg; /* UDP 패킷 크기 */ char FAR *lpVendorInfo; /* 회사별 데이터 구조의 포인터 */ } WSADATA; |
(2) WSACleanup()
▶ 윈속의 사용을 종료할 때 호출하며 WSAStartup()에 대응되는 함수이다.
'Info' 카테고리의 다른 글
Info - AP 모드 설정하기 (0) | 2016.08.31 |
---|---|
Info - 소켓 설명 사이트 (0) | 2016.08.31 |
Info - MSDN samples 주소 (0) | 2016.08.31 |
Info - ASCII code table (0) | 2016.08.31 |
Info - 이동통신관련 좋은 블로그 (0) | 2016.08.31 |