生活随笔
收集整理的這篇文章主要介紹了
                                
【网络编程】之八、异步选择WSAAsyncSelect
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.                        
 
                                
                            
                            
                             大家用這個(gè)模型,可以讓應(yīng)用程序在一個(gè)套接字上接收以windows消息為基礎(chǔ)的網(wǎng)絡(luò)事件通知。我們想要用這個(gè)操作,具體的做法就是我們建立一個(gè)套接字,然后調(diào)用WSAAsyncSelect函數(shù), 也就是說,這個(gè)模型的核心就是我們的這個(gè)函數(shù);
 
 來看一下函數(shù)原型:
 
 
 
   [cpp]?view plaincopy     
 int?WSAAsyncSelect(?? ??_In_??SOCKET?s,?? ??_In_??HWND?hWnd,?? ??_In_??unsigned?int?wMsg,?? ??_In_??long?lEvent?? );?? 
 
 
對于最后一個(gè)參數(shù),在這里要說一下,他包括的網(wǎng)絡(luò)事件模型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE。 
 
 
 到底使用FD_ACCEPT,還是使用FD_CONNECT類型,要取決于應(yīng)用程序的身份是客戶端,還是服務(wù)器。我們可以用或運(yùn)算來一起使用;
 
 
 FD_READ 應(yīng)用程序想要接收有關(guān)是否可讀的通知,以便讀入數(shù)據(jù)
 FD_WRITE 應(yīng)用程序想要接收有關(guān)是否可寫的通知,以便寫入數(shù)據(jù)
 FD_ACCEPT 應(yīng)用程序想接收與進(jìn)入連接有關(guān)的通知
 FD_CONNECT ? 應(yīng)用程序想接收與一次連接完成的通知
 FD_CLOSE 應(yīng)用程序想接收與套接字關(guān)閉的通知
 
 
 實(shí)例:
 
   [cpp]?view plaincopy     
 WSAAsyncSeltct(s,?hwnd,?WM_SOCKET,?FD_CONNECT?|?FD_READ?|?FD_WRITE?|?FD_CLOSE);?? 
 
應(yīng)用程序可以在套接字s上,接收到有關(guān)連接,發(fā)送,接收以及套接字關(guān)閉的一系列通知了。
 
 
 
 
 
 
 要注意的是:通過上面的函數(shù)原型我們可以看出來,要想使用我們的這個(gè)模型,必須要先調(diào)用CreateWindow函數(shù)來創(chuàng)建一個(gè)窗口,然后再為窗口提供一個(gè)窗口例程函數(shù)(WinProc);
 
 
 
 
 這里要說的注意是:
 
 當(dāng)你有多個(gè)事件的時(shí)候,你一定要在套接字上一次注冊,一旦你在這個(gè)套接字上允許了事件通知,那么以后除非你明確的調(diào)用closesocket命令或者由應(yīng)用程序針對的那個(gè)套接字調(diào)用了WSAAsyncSelect,那么你就更改了注冊的網(wǎng)絡(luò)事件的類型了,否則的話事件通知就會永遠(yuǎn)有效。 ?上面函數(shù)你最后一個(gè)參數(shù)設(shè)置為0,效果相當(dāng)于你停止在套接字上進(jìn)行的所有網(wǎng)絡(luò)事件通知。
 
 
 
 
 還有就是你的應(yīng)用程序針對一個(gè)套接字調(diào)用了WSAAsyncSelect,那么套接字會從“鎖定”模式變成“非鎖定”模式。 ? ?這樣以后,會導(dǎo)致錯(cuò)誤。 ? ? 為了防止錯(cuò)誤的產(chǎn)生,應(yīng)用程序依賴于由WSAAsyncSelect的第三個(gè)參數(shù)指定的用戶自定義窗口消息,來判斷網(wǎng)絡(luò)事件類型何時(shí)在套接字上發(fā)生,不能盲目的調(diào)用。
 
 
 
 
 當(dāng)你的程序調(diào)用WSAAsyncSelect成功后,會在和hWnd窗口句柄對應(yīng)的窗口以windows消息的形式接受網(wǎng)絡(luò)事件的通知。
 
 看窗口消息如何定義:
 
 
 
   [cpp]?view plaincopy     
 LRESULT?CALLBACK?WindowProc(??? ????HWND?hwnd,?? ????UINT?uMsg,?? ????WPARAM?wParam,?? ????LPARAM?lParam?? );?? 
 
 
來看一下步驟:當(dāng)網(wǎng)絡(luò)消息抵達(dá)窗口后,應(yīng)用程序就會先檢查lParam的高字節(jié)位,以判斷是否是在網(wǎng)絡(luò)錯(cuò)誤。WSAGETSELECTERROR這個(gè)宏可返回高字節(jié)位包含的錯(cuò)誤信息。 
 
 
 然后如果程序沒有發(fā)現(xiàn)套接字上沒產(chǎn)生錯(cuò)誤,接著就要調(diào)查到底是那個(gè)網(wǎng)絡(luò)事件類型,具體做法是讀取lParam的低字節(jié)位。 ?WSAGETSELECTEVENT這個(gè)宏返回lParam的低字節(jié)部分。
 
 
 
 
 看一下代碼:
 
 
 
   [cpp]?view plaincopy     
 #include<Windows.h>?? #include<tchar.h>?? ?? #define?MSGSIZE?1024?? #define?WM_SOCKET?WM_USER+100?? ?? #pragma?comment(lib,?"ws2_32.lib")?? ?? LRESULT?CALLBACK?WindowProc(HWND?hwnd,?UINT?uMsg,?WPARAM?wParam,?LPARAM?lParam);?? ?? int?WINAPI?WinMain(?__in?HINSTANCE?hInstance,?__in_opt?HINSTANCE?hPrevInstance,?__in?LPSTR?lpCmdLine,?__in?int?nShowCmd?)?? {?? ????TCHAR?classname[]?=?"AsyncSelect";?? ?? ????WNDCLASS?wndclass;????? ????wndclass.style?=?CS_HREDRAW?|?CS_VREDRAW;?? ????wndclass.lpfnWndProc?=?WindowProc;?? ????wndclass.cbClsExtra?=?0;?? ????wndclass.cbWndExtra?=?0;?? ????wndclass.hInstance?=?hInstance;?? ????wndclass.hIcon?=?LoadIcon(NULL,?IDI_APPLICATION);?? ????wndclass.hCursor?=?LoadCursor(NULL,?IDC_ARROW);?? ????wndclass.hbrBackground?=?(HBRUSH)GetStockObject(WHITE_BRUSH);?? ????wndclass.lpszMenuName?=?NULL;?? ????wndclass.lpszClassName?=?classname;?? ?????? ????if?(!RegisterClass(&wndclass))?? ????{?? ????????MessageBox(NULL,?"register?class?error",?classname,?MB_ICONERROR);?? ????????return?0;?? ????}?? ?????? ????HWND?hwnd?=?CreateWindow(classname,?"AsyncSelect?Model",?WS_OVERLAPPEDWINDOW,?? ????????CW_USEDEFAULT,?CW_USEDEFAULT,?CW_USEDEFAULT,?CW_USEDEFAULT,??? ????????NULL,?NULL,?hInstance,?NULL);?? ?????? ????ShowWindow(hwnd,?nShowCmd);?? ????UpdateWindow(hwnd);?? ?? ????MSG?msg;?? ?????? ????while?(GetMessage(&msg,?NULL,?0,?0))?? ????{?? ????????TranslateMessage(&msg);?? ????????DispatchMessage(&msg);?? ????}?? ?? ????return?msg.wParam;?? }?? ?? LRESULT?CALLBACK?WindowProc(HWND?hwnd,?UINT?uMsg,?WPARAM?wParam,?LPARAM?lParam)?? {?? ????WSADATA?wsd;?? ????static?SOCKET?slisten;?? ????SOCKET?sClient;?? ????SOCKADDR_IN?local,?client;?? ????int?ret,?iAddrsize?=?sizeof(client);?? ????char?szMessage[MSGSIZE]?=?{0};?? ?? ????switch?(uMsg)?? ????{?? ????case?WM_DESTROY:?? ????????{?? ?????????????? ????????????closesocket(slisten);?? ????????????WSACleanup();?? ????????????PostQuitMessage(0);?? ????????????return?0;?? ????????}?? ????case?WM_CREATE:?? ????????{?? ?????????????? ????????????WORD?sockVersion?=?MAKEWORD(2,?0);?? ????????????WSAStartup(sockVersion,?&wsd);?? ?????????????? ????????????slisten?=?socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);?? ?? ????????????local.sin_family?=?AF_INET;?? ????????????local.sin_port?=?htons(8888);?? ????????????local.sin_addr.S_un.S_addr?=?htonl(INADDR_ANY);?? ?????????????? ????????????if(bind(slisten,?(sockaddr*)&local,?sizeof(local))?==?SOCKET_ERROR)?? ????????????{?? ????????????????WSACleanup();?? ????????????????return?0;?? ????????????}?? ?????????????? ????????????if(listen(slisten,?5)?==?SOCKET_ERROR)?? ????????????{?? ????????????????WSACleanup();?? ????????????????return?0;?? ????????????}?? ?????????????? ????????????WSAAsyncSelect(slisten,?hwnd,?WM_SOCKET,?FD_ACCEPT);?? ????????????return?0;?? ????????}?? ?? ????case?WM_SOCKET:?? ????????{?? ????????????if?(WSAGETSELECTERROR(lParam))?? ????????????{?? ????????????????closesocket(wParam);?? ????????????????break;?? ????????????}?? ?? ????????????switch(WSAGETSELECTEVENT(lParam))?? ????????????{?? ????????????case?FD_ACCEPT:?? ????????????????{?? ?????????????????????? ????????????????????sClient?=?accept(wParam,?(sockaddr*)&client,?&iAddrsize);?? ?????????????????????? ????????????????????WSAAsyncSelect(sClient,?hwnd,?WM_SOCKET,?FD_READ|FD_CLOSE);?? ????????????????????break;?? ????????????????}?? ????????????case?FD_READ:?? ????????????????{?? ?????????????????????? ????????????????????ret?=?recv(wParam,?szMessage,?MSGSIZE,?0);?? ?? ????????????????????if?(ret?==?0?||?ret?==?SOCKET_ERROR?&&?WSAGetLastError()?==?WSAECONNRESET)?? ????????????????????{?? ????????????????????????closesocket(wParam);?? ????????????????????}?? ????????????????????else?? ????????????????????{?? ?????????????????????????? ????????????????????????szMessage[ret]?=?'\0';?? ????????????????????????send(wParam,?szMessage,?strlen(szMessage),?0);?? ????????????????????}?? ????????????????????break;?? ????????????????}?? ????????????case?FD_CLOSE:?? ????????????????{?? ????????????????????closesocket(wParam);?? ????????????????????break;?? ????????????????}?? ????????????default:?? ????????????????{?? ????????????????????closesocket(wParam);?? ????????????????????break;?? ????????????????}?? ????????????}?? ????????}?? ????????return?0;?? ????}?? ?? ????return?DefWindowProc(hwnd,?uMsg,?wParam,?lParam);?? }?? 
 
 
 
 
 
                2012/9/2
  jofranks于南昌
               
 
  版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
                            總結(jié)
                            
                                以上是生活随笔為你收集整理的【网络编程】之八、异步选择WSAAsyncSelect的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。