千家信息网

WSAAsyncSelect 模型

发表于:2025-01-27 作者:千家信息网编辑
千家信息网最后更新 2025年01月27日,Winsock 提供了一个有用的异步I/O模型。利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函
千家信息网最后更新 2025年01月27日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安全错误 数据库的锁怎样保障安全 吴英骏 数据库 数据库得到系统时间 应用无法连接数据库是什么原因 暗黑2角色在其他服务器什么意思 网络安全法 要求做等保 软件开发每天写不完的文档 阳泉商场触摸屏软件开发公司 成都net软件开发费用是多少 数据库保存文件夹怎么打开 南京移动医疗健康软件开发 林夕网络安全团队 西藏远程服务器租赁收费 蛋大数据库 网易服务器为什么这么便宜 买手机一直显示服务器未接入 江阴浪潮服务器维修服务点 深圳市杰德网络技术有限公司 微信小程序购物软件开发 信息与网络技术基础测试 网络安全100字左右作文 域名换服务器影响排名吗 奉化企业软件开发哪家好 办公大楼效果图软件开发 2021 中国网络安全融资 北京美客美网络技术有限公司 wifi连接显示主服务器异常 服务器采购合同范本 刺激战场外服服务器有哪些 网络安全犯罪举报网站 网络安全警语
0