WSAAsyncSelect 모델
WSAAsyncSelect() 함수가 핵심적인 역할을 한다는 뜻에서 붙인 이름
이 모델을 사용하면 윈도우 메시지 형태로 소켓과 관련된 네트워크 이벤트를 처리할 수 있다.
모든 소켓과 관련 메시지는 하나의 윈도우, 즉 하나의 윈도우 프로시저로 전달되므로 멀티스레드를 사용하지 않고도
여러 소켓을 처리 할 수 있다.
입출력 절차
1) WSAAsyncSelect() 함수를 이용하여 소켓을 위한 윈도우 메시지와 처리할 네트워크 이벤트를 등록한다.
ex) 소켓을 통해 데이터를 보내거나 받을 수 있는 상황이 되면 특정 윈도우 메시지로 알려달라는 내용을 등록한다.
2) 등록한 네트워크 이벤트가 발생하면 윈도우 메시지가 발생하고 윈도우 프로시저가 호출된다.
3) 윈도우 프로시저에서는 받은 메시지의 종류에 따라 적절한 소켓 함수를 호출하여 처리한다.
WSAAsyncSelect() 함수 원형
int WSAAsyncSelect ( SOCKET s, HWND hwnd, unsigned int wMsg, long lEvent);
1) 처리하고자 하는 소켓
2) 메시지를 받을 윈도우를 나타내는 핸들값
3) 윈도우가 받을 메시지 소켓을 위한 메시지는 따로 정의되어 있지 않으므로 사용자 정의 메시지를 이용한다.
4) 처리할 네트워크 이벤트 종료를 비트 마스크 조합으로 나타낸다.
FD_ACCEPT : 클라이언트가 접속하면 윈도우 메시지 발생
FD_READ : 데이터 수신 가능하면 윈도우 메시지 발생
FD_WRITE : 데이터 송신이 가능하면 윈도우 메시지 발생
FD_CLOSE : 상대가 접속을 종료하면 윈도우 메시지 발생
FD_CONNECT : 접속이 완료되면 윈도우 메시지를 발생
ex) 소켓 S에 대해 FD_READ & FD_WRITE 이벤트를 등록하는 예
#define WM_SOCKET (WM_USER + 1)
..
WSAAsyncSelect(s, hwnd, WM_SOCKET, FD_READ|FD_WRITE);
---------------------------------------------------------------------------------------
사용 예)
WSADATA wsa;
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0)
return -1;
SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if(listen_sock == INVALID_SOCKET) err_quit("socket()");
retval = WSAAsyncSelect(listen_sock, hWnd,
WM_SOCKET, FD_ACCEPT|FD_CLOSE);
if(retval == SOCKET_ERROR) err_quit("WSAAsyncSelect()");
............. 바인드 리슨등...
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
.......................
switch(uMsg){
case WM_SOCKET: // 소켓 관련 윈도우 메시지
{
if(WSAGETSELECTERROR(lParam)){
err_display(WSAGETSELECTERROR(lParam));
RemoveSocketInfo(wParam);
return;
}// 메시지 처리
switch(WSAGETSELECTEVENT(lParam)){
case FD_ACCEPT:
addrlen = sizeof(clientaddr);
client_sock = accept(wParam, (SOCKADDR *)&clientaddr, &addrlen);
if(client_sock == INVALID_SOCKET){
if(WSAGetLastError() != WSAEWOULDBLOCK)
err_display("accept()");
return;
}
retval = WSAAsyncSelect(client_sock, hWnd,
WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE);
if(retval == SOCKET_ERROR){
err_display("WSAAsyncSelect()");
}
break;case FD_READ:
ptr = GetSocketInfo(wParam);
if(ptr->recvbytes > 0){
ptr->recvdelayed = TRUE;
return;
}
// 데이터 받기
retval = recv(ptr->sock, ptr->buf, BUFSIZE, 0);
if(retval == SOCKET_ERROR){
if(WSAGetLastError() != WSAEWOULDBLOCK){
err_display("recv()");
}
return;
}
..............break;
case FD_WRITE:
ptr = GetSocketInfo(wParam);
if(ptr->recvbytes <= ptr->sendbytes)
return;
// 데이터 보내기
retval = send(ptr->sock, ptr->buf + ptr->sendbytes,
ptr->recvbytes - ptr->sendbytes, 0);
if(retval == SOCKET_ERROR){
if(WSAGetLastError() != WSAEWOULDBLOCK){
err_display("send()");
}
return;
}
ptr->sendbytes += retval;
................
break;
case FD_CLOSE:
RemoveSocketInfo(wParam);
break;
}
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
[출처] WSAAsyncSelect 사용법 (C언어를 배우자) |작성자 노력의산물
'네트워크' 카테고리의 다른 글
소켓 IO overlapped CallBack (0) | 2013.05.22 |
---|---|
IOCP 구현 (0) | 2013.05.22 |
채팅프로그램 메신저 소스 (0) | 2013.05.14 |
c# 비동기 방식의 콜백함수 (0) | 2013.05.14 |
C# 비동기 클라이언트 소켓서버 (0) | 2013.05.14 |