千家信息网

WSAAsyncSelect 模型

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,Winsock 提供了一个有用的异步I/O模型。利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函
千家信息网最后更新 2026年11月02日WSAAsyncSelect 模型

Winsock 提供了一个有用的异步I/O模型。利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函数。该模型最早出现于Winsock的1.1版本中,用于帮助应用程序开发者面向一些早期的16位 Windows平台(如Windows for Workgroups),适应其"落后"的多任务消息环境。应用程序仍可从这种模型中得到好处,特别是它们用一个标准的Windows例程(常称为 "WndProc"),对窗口消息进行管理的时候。该模型亦得到了Microsoft Foundation Class(微软基本类,MFC)对象CSocket的采纳。

#include   #include   #define PORT      5150  #define MSGSIZE   1024  #define WM_SOCKET WM_USER+0  #pragma comment(lib, "ws2_32.lib")  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)  {  static TCHAR szAppName[] = _T("AsyncSelect Model");  HWND         hwnd ;  MSG          msg ;  WNDCLASS     wndclass ;  wndclass.style         = CS_HREDRAW | CS_VREDRAW ;  wndclass.lpfnWndProc   = WndProc ;  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 = szAppName ;  if (!RegisterClass(&wndclass))  {      MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;      return 0 ;  }  hwnd = CreateWindow (szAppName,                  // window class name                         TEXT ("AsyncSelect Model"), // window caption                         WS_OVERLAPPEDWINDOW,        // window style                         CW_USEDEFAULT,              // initial x position                         CW_USEDEFAULT,              // initial y position                         CW_USEDEFAULT,              // initial x size                         CW_USEDEFAULT,              // initial y size                         NULL,                       // parent window handle                         NULL,                       // window menu handle                         hInstance,                  // program instance handle                         NULL) ;                     // creation parameters  ShowWindow(hwnd, iCmdShow);  UpdateWindow(hwnd);  while (GetMessage(&msg, NULL, 0, 0)) //获取消息  {      TranslateMessage(&msg) ;  //转化键盘信息      DispatchMessage(&msg) ; //将信息发送到指定窗体  }    return msg.wParam;  }  LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  {  WSADATA       wsd;  static SOCKET sListen;  SOCKET        sClient;  SOCKADDR_IN   local, client;  int           ret, iAddrSize = sizeof(client);  char          szMessage[MSGSIZE];  switch (message)  {  case WM_CREATE:      // Initialize Windows Socket library     WSAStartup(0x0202, &wsd);         // Create listening socket      sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);           // Bind      local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);     local.sin_family = AF_INET;     local.sin_port = htons(PORT);     bind(sListen, (struct sockaddr *)&local, sizeof(local));         // Listen      listen(sListen, 3);      // Associate listening socket with FD_ACCEPT event     WSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT);     return 0;  case WM_DESTROY:      closesocket(sListen);      WSACleanup();      PostQuitMessage(0);      return 0;    case WM_SOCKET:      if (WSAGETSELECTERROR(lParam))      {        closesocket(wParam);        break;      }            switch (WSAGETSELECTEVENT(lParam))      {      case FD_ACCEPT:        // Accept a connection from client        sClient = accept(wParam, (struct sockaddr *)&client, &iAddrSize);                // Associate client socket with FD_READ and FD_CLOSE event        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;      }      return 0;  }  //把我们不处理的信息交给系统作默认处理  return DefWindowProc(hwnd, message, wParam, lParam);  }


在我看来,WSAAsyncSelect是最简单的一种Winsock I/O模型(之所以说它简单是因为一个主线程就搞定了)。使用Raw Windows API写过窗口类应用程序的人应该都能看得懂。这里,我们需要做的仅仅是:
1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;
2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用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

应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知


应用程序 程序 应用 套接字 消息 模型 事件 函数 处理 监听 有关 信息 数据 网络 系统 质量 变化 服务 清楚 没什么 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 手磨咖啡 深圳恒合互联网络科技有限公司 美国互联网科技 互联网 卓越科技 互联网金融科技创新 互联网科技ppt模板 苏州大垚互联网科技 互联网科技公司介绍 华脉科技工业互联网产品 湖南洣水互联网科技有限公司扣款 广州慧亚互联网科技怎么样 金融科技与互联网金融相同和不同 互联网和黑科技的看法 广州新华互联网科技学校电竞方面 皮皮虾互联网科技有限公司 新氧科技和美国互联网有关系吗 昆明中奇联合互联网科技 江苏互联网智能科技产品出厂价 互联网科技创业计划的风险分析 广州全民伙伴互联网科技有限公司 互联网佳科技有限公司 猪兼强互联网科技 互联网科技的未来发展 居家互联网科技有限公司 深圳市罗太互联网科技有限公司 互联网与数字科技关系 江苏互联网科技小贷 杭州科技互联网公司有哪些 恒生互联网科技趋势 六子台科技互联网展会
0