오다기리 박의 알고리즘 노트

[WIN32 API] 9. 윈도우 소켓 프로그래밍 본문

WIN32 API

[WIN32 API] 9. 윈도우 소켓 프로그래밍

오다기리 박 2018. 1. 9. 17:46

9. 윈도우 소켓 프로그래밍


■ 소켓 연결하기

- 소켓 : IP주소와 포트번호로 이루어진 컴퓨터 통신의 끝점. 표준화된 인터페이스를 제공


⠂소켓 프로그래밍을 위한 구조체

- 윈도우 소켓 초기화 정보를 가지고 있는 구조체

typedef struct WSAData {

       WORD                    wVersion;

       WORD                    wHighVersion;

       char                        szDescription[WSADESCRIPTION_LEN+1];

       char                        szSystemStatus[WSASYS_STATUS_LEN+1];

       unsigned short        iMaxSockets;

       unsigned short        iMaxUdpDg;

       char FAR *              lpVendorInfo;

};

- 소켓을 연결할 대상의 주소를 쓰는 구조체

struct sockaddr_in {

       short   sin_family;

       u_short sin_port;

       struct  in_addr sin_addr;

       char    sin_zero[8];

};


⠂소켓 통신을 위한 함수

- 윈속 사용시작하기(서버,클라)

int FAR WSAStartup(

WORD wVersionRequired,    //사용할 윈도우 소켓 버전

LPWSADATA lpWSAData   //소켓 정보 저장 공간

);


- 소켓 생성하기(서버,클라)

SOCKET WSAAPI socket (

int af, //address family 명시. AF_INET 이용

int type, //소켓 유형. SOCK_STREAM 이용

int protocol //0 입력

);


- 주소와 소켓 연결하기(서버)

BOOL bind (

          SOCKET s, //연결할 소켓

          const SOCKADDR* lpSockAddr, //소켓에 지정할 주소와 포트 번호를 포함하는

//SOCKADDR구조체 주소

          int nSockAddrLen //주소를 저장하는 구조체 SOCKADDR크기

);


- 연결 요구 기다리기(서버)

int PASCAL FAR listen (

           SOCKET s, //기다릴 소켓

           int backlog //대기할 수 있는 요구 최대 개수 1~5

);


- 연결 요구하기(클라)

BOOL connect (

          SOCKET s, //연결에 사용할 소켓

          struct SOCKADDR* lpSockAddr, //상대의 주소와 포트번호

          int nSockAddrLen //주소를 저장하는 구조체 SOCKADDR크기

);


- 연결 요구 받아들이기(서버)

SOCKET accept(

SOCKET s, //소켓에 대한 요구를 받아들임

SOCKADDR* lpSockAddr, //접속하는 상대방의 주소를 저장할

//SOCKADDR구조체 주소

int* lpSockAddrLen //주소를 저장하는 구조체 SOCKADDR크기

); -> 클라이언트와 연결할 소켓을 반환한다.


- 소켓과 관련된 리소스 해제하기(서버,클라)

int closesocket(SOCKET s);


- 윈속 사용 끝내기(서버,클라)

int WSACleanup();


■ 메시지 교환하기


⠂메시지 송수신 함수

- 메시지 전송하기

int send(

SOCKET s, //연결된 소켓

const void* lpBuf, //보낼 메시지가 저장된 버퍼

int nBufLen, //메시지의 길이

int nFlags //0

); -> 보낸 메시지 길이 반환


- 메시지 수신하기

int recv(

SOCKET s, //연결된 소켓

void* lpBuf, //받는 메시지가 저장될 버퍼

int nBufLen, //버퍼의 길이

int nFlags //0

); -> 받은 메시지 길이 반환



⠂문자집합 변환 함수

- 멀티바이트-> 유니코드 변환

int MultiByteToWideChar(

   _In_ UINT CodePage, //ANSI문자열에 대한 언어. CP_ACP

   _In_ DWORD dwFlags, //0

   _In_ LPCSTR lpMultiByteStr, //변환하려는 멀티바이트 문자열

   _In_ int cbMultiByte, //문자열의 길이. -1이면 자동계산

   _Out_opt_ LPWSTR lpWideCharStr, //유니코드로 변환 후 저장될 공간

   _In_ int cchWideChar //유니코드 문자열의 길이

   );

* 5,6 번째를 NULL로 설정시 실제로 변환하지 않고 변환했을 경우의 유니코드 문자열 길이 값을 반환


- 유니코드 -> 멀티바이트 변환

int WideCharToMultiByte(

   _In_ UINT CodePage, //ANSI문자열에 대한 언어. CP_ACP

   _In_ DWORD dwFlags, //0

   _In_ LPCSTR lpWideCharStr, //변환하려는 유니코드 문자열

   _In_ int cchWidChar, //문자열의 길이. -1이면 자동계산

   _Out_opt_ LPWSTR lpMultiByteStr, //멀티바이트로 변환 후 저장될 공간

   _In_ int cbMultiByte //변환 후 문자열의 길이

   _In_opt_ LPCSTR lpDefaultChar, //NULL

   _Out_opt LPBOOL lpUsedDefaultChar //NULL

   );

* 5,6 번째를 NULL로 설정시 실제로 변환하지 않고 변환했을 경우의 멀티바이트 문자열 길이 값을 반환

■ 논블로킹 통신

⠂논블로킹 통신 : 서버가 무한정 기다리지 않고 다른 일을 하다가 연결을 시도하는 신호가 도착하거나 통신 메시지가 도착하면 사용자가 정의한 윈도우 메시지를 보내는 방식


⠂윈도우 메시지, 네트워크 이벤트 등록 함수

int WSAAsyncSelect(

SOCKET s, //연결된 소켓

HWND hwnd, //메시지가 발생하는 윈도우 핸들

unsigned int iMsg, //등록될 윈도우 메시지

long IEvent //등록될 네트워크 이벤트

);

-> 서버소켓에서 상대방에 의해 네트워크 이벤트가 발생하면 윈도우 메시지(WM_ASYNC)를 hwnd윈도우에 발생시키기 위해 설정한다.


iMsg

lParam(네트워크 이벤트)





WM_ASYNC

FD_READ

읽을 준비가 되면 발생

FD_WRITE

읽을 데이터가 사용 가능하면 발생

FD_OOB

통신 과정에서 긴급히 전송되는 out-of-band 데이터가 도착하면 발생

FD_ACCEPT

접속을 요구하는 신호가 오면 발생

FD_CONNECT

접속이 완료되면 발생

FD_CLOSE

상대방이 접속을 종료하면 발생