WSAAsyncSelect模型
WSAAsyncSelect模型允許應用程式以Windows訊息的接收網路事件通知。這個模型是為了適應Windows的訊息驅動環境而設定的,現在許多對效能要求不高的網路應用程式都採用WSAAsyncSelect模型,MFC中的CSocket類也使用了它。
WSAAsyncSelect函數自動把通訊端設為非阻塞模式,並且為通訊端綁定一個視窗控制代碼和發送哪些通知碼(FD_READ之類的)。當有網路事件發生時,便向這個視窗發送程式自訂的訊息。
具體編程流程:
1、 自訂一個與網路通知訊息,用於通知WSAsyncSelect綁定中的視窗。
2、 建立一個視窗,用於WSAAsyncSelect綁定到指定的通訊端。
3、 編寫上述視窗的訊息處理函數。在收到自訂網路通知訊息後,提取出相應錯誤碼和網路事(FD_ACCEPT、
FD_READ、FD_WRIET、FD_CLOSE),並作出相應的處理。
#define _WIN32_WINNT 0x0400 #include<windows.h>#include<cstdio>#include"InitSocket.h"//需要自訂一個訊息#define WM_SOCKET WM_USER+1CInitSock initSock ; //進入main函數前已經進行了初始化LONG CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) ;int main(void){char szClassName[] = "MainWClass" ;WNDCLASSEX wndclass ;wndclass.cbSize = sizeof(wndclass) ;wndclass.style = CS_HREDRAW|CS_VREDRAW ;wndclass.lpfnWndProc = WindowProc ;wndclass.cbClsExtra = 0 ;wndclass.cbWndExtra = 0 ;wndclass.hInstance = NULL ;wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION) ;wndclass.hCursor = LoadCursor(NULL,IDC_ARROW) ;wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;wndclass.lpszMenuName = NULL ;wndclass.lpszClassName = szClassName ;wndclass.hIconSm = NULL ;RegisterClassEx(&wndclass) ;//建立主視窗HWND hWnd = CreateWindowEx(0,szClassName,"",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,NULL,NULL ) ;if(NULL == hWnd){MessageBox(NULL,"建立視窗出錯!","error",MB_OK) ;return -1 ;} USHORT nPort = 4567 ;SOCKET sListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP) ;sockaddr_in sin ;sin.sin_family = AF_INET ;sin.sin_port = htons(nPort) ;sin.sin_addr.s_addr = INADDR_ANY ;if(bind(sListen,(sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR){printf("Failed bind()\n") ;return -1 ;}//將通訊端設為視窗通知訊息類型,自動將通訊端設定為非阻塞模式WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE) ;listen(sListen,5) ;MSG msg ;while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg) ;DispatchMessage(&msg) ;}return msg.wParam ;}LONG CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) {switch(uMsg){case WM_SOCKET :{SOCKET s = wParam ;if(WSAGETSELECTERROR(lParam)){closesocket(s) ;return 0 ;}switch(WSAGETSELECTEVENT(lParam)){case FD_ACCEPT :{SOCKET client = accept(s,NULL,NULL) ;WSAAsyncSelect(client,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE) ;printf("接收一個串連\n") ;}break ;case FD_WRITE:break ;case FD_READ :{char szText[1024] = {0} ;if(recv(s,szText,1024,0) == SOCKET_ERROR){closesocket(s) ;}else{printf("接收資料:%s",szText) ;}break ;}case FD_CLOSE :{printf("關閉一個串連\n") ;closesocket(s);}break ;}return 0 ;}case WM_DESTROY :PostQuitMessage(0) ;return 0 ;}//將我們不處理的訊息交給系統做預設處理return DefWindowProc(hWnd,uMsg,wParam,lParam) ;}