(转)套接字IO模型(二) WSAAsynSelect模型

套接字IO模型(二) WSAAsynSelect模型

   WSAAsynSelect模型也是一个常用的异步I/O模型。应用程序可以在一个套接字上接收以WINDOWS消息为基础的网络事件通知。该模型的实现方法是通过调用WSAAsynSelect函数自动将套接字设置(转变)为非阻塞模式,并向WINDOWS注册一个或多个网络事件,并提供一个通知时使用的窗口句柄。当注册的事件发生时,对应的窗口将收到一个基于消息的通知。

 

  1  #include  < winsock.h >
  2  #include  < tchar.h >
  3 
  4  #define  PORT         5150
  5  #define  MSGSIZE      1024
  6  #define  WM_SOCKET WM_USER+0
  7 
  8  #pragma  comment(lib, "ws2_32.lib")
  9 
 10  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 11 
 12  int  WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine,  int  iCmdShow)
 13  {
 14        static  TCHAR szAppName[]  =  _T( " AsyncSelect Model " );
 15       HWND            hwnd ;
 16       MSG             msg ;
 17       WNDCLASS        wndclass ;
 18 
 19       wndclass.style             =  CS_HREDRAW  |  CS_VREDRAW ;
 20       wndclass.lpfnWndProc       =  WndProc ;
 21       wndclass.cbClsExtra        =   0  ;
 22       wndclass.cbWndExtra        =   0  ;
 23       wndclass.hInstance         =  hInstance ;
 24       wndclass.hIcon             =  LoadIcon (NULL, IDI_APPLICATION) ;
 25       wndclass.hCursor           =  LoadCursor (NULL, IDC_ARROW) ;
 26       wndclass.hbrBackground  =  (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 27       wndclass.lpszMenuName      =  NULL ;
 28       wndclass.lpszClassName  =  szAppName ;
 29 
 30        if  ( ! RegisterClass( & wndclass))
 31       {
 32         MessageBox (NULL, TEXT ( " This program requires Windows NT! " ), szAppName, MB_ICONERROR) ;
 33          return   0  ;
 34       }
 35 
 36       hwnd  =  CreateWindow (szAppName,                      //  window class name
 37                            TEXT ( " AsyncSelect Model " ),  //  window caption
 38                            WS_OVERLAPPEDWINDOW,            //  window style
 39                            CW_USEDEFAULT,                  //  initial x position
 40                            CW_USEDEFAULT,                  //  initial y position
 41                            CW_USEDEFAULT,                  //  initial x size
 42                            CW_USEDEFAULT,                  //  initial y size
 43                            NULL,                           //  parent window handle
 44                            NULL,                           //  window menu handle
 45                            hInstance,                      //  program instance handle
 46                            NULL) ;                         //  creation parameters
 47 
 48       ShowWindow(hwnd, iCmdShow);
 49       UpdateWindow(hwnd);
 50 
 51        while  (GetMessage( & msg, NULL,  0 ,  0 ))
 52       {
 53         TranslateMessage( & msg) ;
 54         DispatchMessage( & msg) ;
 55       }
 56    
 57        return  msg.wParam;
 58  }
 59 
 60  LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 61  {
 62       WSADATA          wsd;
 63        static  SOCKET sListen;
 64       SOCKET           sClient;
 65       SOCKADDR_IN      local, client;
 66        int               ret, iAddrSize  =   sizeof (client);
 67        char              szMessage[MSGSIZE];
 68 
 69        switch  (message)
 70       {
 71  case  WM_CREATE:
 72          //  Initialize Windows Socket library
 73       WSAStartup( 0x0202 ,  & wsd);
 74    
 75        //  Create listening socket
 76         sListen  =  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 77      
 78        //  Bind
 79         local.sin_addr.S_un.S_addr  =  htonl(INADDR_ANY);
 80       local.sin_family  =  AF_INET;
 81       local.sin_port  =  htons(PORT);
 82       bind(sListen, ( struct  sockaddr  * ) & local,  sizeof (local));
 83    
 84        //  Listen
 85         listen(sListen,  3 );
 86 
 87          //  Associate listening socket with FD_ACCEPT event
 88       WSAAsyncSelect(sListen, hwnd, WM_SOCKETFD_ACCEPT);
 89        return   0 ;
 90 
 91        case  WM_DESTROY:
 92         closesocket(sListen);
 93         WSACleanup();
 94         PostQuitMessage( 0 );
 95          return   0 ;
 96    
 97        case  WM_SOCKET:
 98          if  (WSAGETSELECTERROR(lParam)) //lParam的高字节包含了可能出现的任何的错误代码
 99         {
100           closesocket(wParam);
101            break ;
102         }
103      
104          switch  (WSAGETSELECTEVENT(lParam))  //lParam的低字节指定已经发生的网络事件
105         {
106          case  FD_ACCEPT:
107            //  Accept a connection from client
108           sClient  =  accept(wParam, ( struct  sockaddr  * ) & client,  & iAddrSize);
109        
110            //  Associate client socket with FD_READ and FD_CLOSE event
111           WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ  |  FD_CLOSE);
112            break ;
113 
114          case  FD_READ:
115           ret  =  recv(wParam, szMessage, MSGSIZE,  0 );
116 
117            if  (ret  ==   0   ||  ret  ==  SOCKET_ERROR  &&  WSAGetLastError()  ==  WSAECONNRESET)
118           {
119             closesocket(wParam);
120           }
121            else
122           {
123             szMessage[ret]  =   ' /0 ' ;
124             send(wParam, szMessage, strlen(szMessage),  0 );
125           }
126            break ;
127        
128          case  FD_CLOSE:
129           closesocket(wParam);      
130            break ;
131         }
132          return   0 ;
133       }
134    
135        return  DefWindowProc(hwnd, message, wParam, lParam);
136  }

WSAAsyncSelect是最简单的一种Winsock I/O模型(之所以说它简单是因为一个主线程就搞定了)。使用Raw Windows API写过窗口类应用程序的人应该都能看得懂。这里,我们需要做的仅仅是:
1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;
2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字客户端套接字)上发生了某个事件,系统发送消息(WM_SOCKET)给hWnd指向的窗体,而WndProc函数处理所有发往窗体的消息并且message参数被设置为WM_SOCKET
3.在WM_SOCKET的消息处理中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;

4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除Windows Socket library

 

下面这张用于WSAAsyncSelect函数的网络事件类型表可以让你对各个网络事件有更清楚的认识:
表1

FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据 
FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据 
FD_OOB 应用程序想接收是否有带外(OOB)数据抵达的通知 
FD_ACCEPT 应用程序想接收与进入连接有关的通知 
FD_CONNECT 应用程序想接收与一次连接或者多点join操作完成的通知 
FD_CLOSE 应用程序想接收与套接字关闭有关的通知 
FD_QOS 应用程序想接收套接字“服务质量”(QoS)发生更改的通知 
FD_GROUP_QOS     应用程序想接收套接字组“服务质量”发生更改的通知(现在没什么用处,为未来套接字组的使用保留) 
FD_ROUTING_INTERFACE_CHANGE 应用程序想接收在指定的方向上,与路由接口发生变化的通知 
FD_ADDRESS_LIST_CHANGE     应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知

 

转自:http://www.cnblogs.com/NeuqUstcIim/archive/2008/08/14/1268185.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值