zoukankan      html  css  js  c++  java
  • 二.Windows I/O模型之异步选择(WSAAsyncSelect)模型

    1.基于windows消息为基础的网络事件io模型。因此我们必须要在窗口程序中使用该模型。该模型中的核心是调用WSAAsyncSelect函数实现异步I/O。

    2.WSAAsyncSelect函数:注册网络事件函数
    int WSAAsyncSelect(
        SOCKET s,//
        HWND hWnd,//
        unsigned int wMsg,//注意,该消息值应该大于WM_USER(1024)
        long lEvent,//网络事件
        );
    若应用程序针对一个套接字调用了WSAAsyncSelect,那么套接字的模式会从阻塞自动变成非阻塞,这样一来,假如调用了像WSARecv这样的Winsock I/O函数,但当时却并没有数据可用,那么必然会造成调用的失败,并返回WSAEWOULDBLOCK错误。为防止这一点,应用程序应依赖于由WSAAsyncSelect的uMsg参数指定的用户自定义窗口消息,来判断网络事件类型何时在套接字上发生;而不应盲目地进行调用。  

    3.网络事件:
    (1)FD_READ:读数据
    (2)FD_WRITE:写数据
    (3)FD_ACCEPT:接收连接
    (4)FD_CONNECT:连接
    (5)FD_CLOSE:关闭
    各个事件可以进行或运算。特别要注意的是,多个事件务必在套接字上一次注册!另外还要注意的是,一旦在某个套接字上允许了事件通知,那么以后除非明确调用closesocket命令,或者由应用程序针对那个套接字调用了WSAAsyncSelect,从而更改了注册套接字的网络事件类型,否则的话,事件通知会永远有效!若将lEvent参数设为0,效果相当于停止在套接字上进行的所有网络事件通知。

    4.在异步选择模型中,还需要自定义窗口消息处理函数。来对各种网络事件进行处理。该函数定义和win32窗口中的窗口消息处理函数相同。原型如下:
    LRESULT CALLBACK WindowProc(
        HWND hWnd,//
        UINT uMsg,//
        WPARAM wParam,//
        LPARAM lParam
        )
    参数lParam的低字(低位字)指定了已经发生的网络事件,而lParam的高字(高位字)包含了可能出现的任何错误代码。
    网络事件消息抵达一个窗口例程后,应用程序首先应检查lParam的高字位,以判断是否在套接字上发生了一个网络错误。这里有一个特殊的宏WSAGETSELECTERROR,可用它返回高字位包含的错误信息。若套接字上没有产生任何错误,接着便应判断到底是哪个网络事件发生。具体的做法便是读取lParam低字节的内容。此时可使用另一个特殊的宏:WSAGETSELECTEVENT,用它返回lParam低字节的内容。

    5.最后一个特别有价值的问题是应用程序如何对FD_WRITE事件进行处理。只有在三
    种条件下,才会发出FD_WRITE通知:
    (1)使用connect或WSAConnect,一个套接字首次建立了连接。
    (2)使用accept或WSAAccept,套接字被接受以后。
    (3)若send、WSASend、sendto或WSASendto操作失败,返回了WSAWOULDBLOCK错误,而且缓冲区的空间变得可用
    因此,作为一个应用程序,自收到首条FD_WRITE消息开始,便应认为自己必然能在一个套接字上发出数据,直至一个send、WSASend、sendto或WSASendto返回套接字错误WSAWOULDBLOCK。经过了这样的失败以后,要再用另一条FD_WRITE通知应用程序再次发送数据。

    示例代码:

     1 #define WM_SOCKET WM_USER+1
     2 #include<Windows.h>
     3 
     4 int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
     5 {
     6     //初始化
     7      SOCKET listen;
     8     HWND window;
     9     window=CreateWindow(...);//这一步并没有多大必要
    10 
    11     WSAStartUp(...);
    12     listen=socket(...);
    13 
    14     //绑定地址
    15     ...
    16 
    17     
    18     //注册网络事件
    19     WSAAsyncSelect(listen,window,WM_SOCKET,FD_ACCEPT|FD_CLOSE);
    20 
    21     //转发消息
    22     SendMessage(...);
    23     
    24 }
    25 
    26 //窗口消息处理函数
    27 BOOL CALLBACK ServerWinProc(HWND hWnd,WORD wMsg,WPARAM wParam,LPARAM lParam)
    28 {
    29     SOCKET Accept;
    30 
    31     case WM_PAINT:
    32         ..
    33         break;
    34     case WM_SOCKET:
    35         if(WSAGETSELECTERROR(lParam))
    36         {
    37             ...
    38             closesocket(Accept);
    39             break;
    40         }
    41         if(WSAGETSELECTEVENT(lParam))
    42         {
    43             case FD_ACCEPT:
    44                 ...
    45                 break;
    46             case FD_CLOSE:
    47                 ...
    48                 break;
    49             case ...
    50         }
    51 }
    View Code
  • 相关阅读:
    Java进阶知识查漏补缺06
    SQL学习记录(concat)
    Restful API学习
    git学习
    获得xmlhttp对象
    vue-cli初接触
    vue初接触
    java使用百度UNIT
    JSON学习
    通用Mapper警告:建议修改基本类型为对应的包装类型!
  • 原文地址:https://www.cnblogs.com/HPAHPA/p/7818836.html
Copyright © 2011-2022 走看看