日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【网络编程】之八、异步选择WSAAsyncSelect

發布時間:2024/4/11 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【网络编程】之八、异步选择WSAAsyncSelect 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家用這個模型,可以讓應用程序在一個套接字上接收以windows消息為基礎的網絡事件通知。我們想要用這個操作,具體的做法就是我們建立一個套接字,然后調用WSAAsyncSelect函數, 也就是說,這個模型的核心就是我們的這個函數;

來看一下函數原型:

[cpp]?view plaincopy
  • int?WSAAsyncSelect(??
  • ??_In_??SOCKET?s,//我們感興趣的套接字??
  • ??_In_??HWND?hWnd,//窗口的句柄,對于網絡事件繁盛后,想要接收到的通知的那個窗口??
  • ??_In_??unsigned?int?wMsg,//指定在發生網絡事件時,打算接收的消息。??
  • ??_In_??long?lEvent//指定一個位掩碼,對應于一系列網絡事件的組合。??
  • );??

  • 對于最后一個參數,在這里要說一下,他包括的網絡事件模型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE。

    到底使用FD_ACCEPT,還是使用FD_CONNECT類型,要取決于應用程序的身份是客戶端,還是服務器。我們可以用或運算來一起使用;

    FD_READ 應用程序想要接收有關是否可讀的通知,以便讀入數據
    FD_WRITE 應用程序想要接收有關是否可寫的通知,以便寫入數據
    FD_ACCEPT 應用程序想接收與進入連接有關的通知
    FD_CONNECT ? 應用程序想接收與一次連接完成的通知
    FD_CLOSE 應用程序想接收與套接字關閉的通知

    實例:

    [cpp]?view plaincopy
  • WSAAsyncSeltct(s,?hwnd,?WM_SOCKET,?FD_CONNECT?|?FD_READ?|?FD_WRITE?|?FD_CLOSE);??
  • 應用程序可以在套接字s上,接收到有關連接,發送,接收以及套接字關閉的一系列通知了。


    要注意的是:通過上面的函數原型我們可以看出來,要想使用我們的這個模型,必須要先調用CreateWindow函數來創建一個窗口,然后再為窗口提供一個窗口例程函數(WinProc);


    這里要說的注意是:

    當你有多個事件的時候,你一定要在套接字上一次注冊,一旦你在這個套接字上允許了事件通知,那么以后除非你明確的調用closesocket命令或者由應用程序針對的那個套接字調用了WSAAsyncSelect,那么你就更改了注冊的網絡事件的類型了,否則的話事件通知就會永遠有效。 ?上面函數你最后一個參數設置為0,效果相當于你停止在套接字上進行的所有網絡事件通知。


    還有就是你的應用程序針對一個套接字調用了WSAAsyncSelect,那么套接字會從“鎖定”模式變成“非鎖定”模式。 ? ?這樣以后,會導致錯誤。 ? ? 為了防止錯誤的產生,應用程序依賴于由WSAAsyncSelect的第三個參數指定的用戶自定義窗口消息,來判斷網絡事件類型何時在套接字上發生,不能盲目的調用。


    當你的程序調用WSAAsyncSelect成功后,會在和hWnd窗口句柄對應的窗口以windows消息的形式接受網絡事件的通知。

    看窗口消息如何定義:

    [cpp]?view plaincopy
  • LRESULT?CALLBACK?WindowProc(???
  • ????HWND?hwnd,//一個窗口句柄,對窗口的調用就是由這個窗口發出的??
  • ????UINT?uMsg,//指定需要對那些消息進行處理。??
  • ????WPARAM?wParam,//指定在上面發生了一個網絡事件的套接字。??
  • ????LPARAM?lParam//低字節制定了已經發生的網絡事件,高字節包含了可能出現的錯誤代碼。??
  • );??

  • 來看一下步驟:當網絡消息抵達窗口后,應用程序就會先檢查lParam的高字節位,以判斷是否是在網絡錯誤。WSAGETSELECTERROR這個宏可返回高字節位包含的錯誤信息。

    然后如果程序沒有發現套接字上沒產生錯誤,接著就要調查到底是那個網絡事件類型,具體做法是讀取lParam的低字節位。 ?WSAGETSELECTEVENT這個宏返回lParam的低字節部分。


    看一下代碼:

    [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);??
  • ????????????//創建socket??
  • ????????????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);??
  • ????????????//綁定socket??
  • ????????????if(bind(slisten,?(sockaddr*)&local,?sizeof(local))?==?SOCKET_ERROR)??
  • ????????????{??
  • ????????????????WSACleanup();??
  • ????????????????return?0;??
  • ????????????}??
  • ????????????//監聽socket??
  • ????????????if(listen(slisten,?5)?==?SOCKET_ERROR)??
  • ????????????{??
  • ????????????????WSACleanup();??
  • ????????????????return?0;??
  • ????????????}??
  • ????????????//注冊監聽socket?FD_ACCEPT事件,當socket有連接時,會發送WM_SOCKET消息給窗口??
  • ????????????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);??
  • ????????????????????//注冊客戶socket?FD_READ和FD_CLOSE事件??
  • ????????????????????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于南昌

    版權聲明:本文為博主原創文章,未經博主允許不得轉載。

    總結

    以上是生活随笔為你收集整理的【网络编程】之八、异步选择WSAAsyncSelect的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。