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
  • 相关阅读:
    外校培训前三节课知识集合纲要(我才不会告诉你我前两节只是单纯的忘了)
    floyd算法----牛栏
    bfs开始--马的遍历
    (DP 线性DP 递推) leetcode 64. Minimum Path Sum
    (DP 线性DP 递推) leetcode 63. Unique Paths II
    (DP 线性DP 递推) leetcode 62. Unique Paths
    (DP 背包) leetcode 198. House Robber
    (贪心 复习) leetcode 1007. Minimum Domino Rotations For Equal Row
    (贪心) leetcode 452. Minimum Number of Arrows to Burst Balloons
    (字符串 栈) leetcode 921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/HPAHPA/p/7818836.html
Copyright © 2011-2022 走看看