大家用这个模型,可以让应用程序在一个套接字上接收以windows消息为基础的网络事件通知。我们想要用这个操作,具体的做法就是我们建立一个套接字,然后调用WSAAsyncSelect函数, 也就是说,这个模型的核心就是我们的这个函数;

来看一下函数原型:

[cpp] view plaincopy
  1. int WSAAsyncSelect(
  2. _In_  SOCKET s,//我们感兴趣的套接字
  3. _In_  HWND hWnd,//窗口的句柄,对于网络事件繁盛后,想要接收到的通知的那个窗口
  4. _In_  unsigned int wMsg,//指定在发生网络事件时,打算接收的消息。
  5. _In_  long lEvent//指定一个位掩码,对应于一系列网络事件的组合。
  6. );

对于最后一个参数,在这里要说一下,他包括的网络事件模型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE。

到底使用FD_ACCEPT,还是使用FD_CONNECT类型,要取决于应用程序的身份是客户端,还是服务器。我们可以用或运算来一起使用;

FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据
FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据
FD_ACCEPT 应用程序想接收与进入连接有关的通知
FD_CONNECT   应用程序想接收与一次连接完成的通知
FD_CLOSE 应用程序想接收与套接字关闭的通知

实例:

[cpp] view plaincopy
  1. WSAAsyncSeltct(s, hwnd, WM_SOCKET, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);

应用程序可以在套接字s上,接收到有关连接,发送,接收以及套接字关闭的一系列通知了。

要注意的是:通过上面的函数原型我们可以看出来,要想使用我们的这个模型,必须要先调用CreateWindow函数来创建一个窗口,然后再为窗口提供一个窗口例程函数(WinProc);

这里要说的注意是:

当你有多个事件的时候,你一定要在套接字上一次注册,一旦你在这个套接字上允许了事件通知,那么以后除非你明确的调用closesocket命令或者由应用程序针对的那个套接字调用了WSAAsyncSelect,那么你就更改了注册的网络事件的类型了,否则的话事件通知就会永远有效。  上面函数你最后一个参数设置为0,效果相当于你停止在套接字上进行的所有网络事件通知。

还有就是你的应用程序针对一个套接字调用了WSAAsyncSelect,那么套接字会从“锁定”模式变成“非锁定”模式。    这样以后,会导致错误。     为了防止错误的产生,应用程序依赖于由WSAAsyncSelect的第三个参数指定的用户自定义窗口消息,来判断网络事件类型何时在套接字上发生,不能盲目的调用。

当你的程序调用WSAAsyncSelect成功后,会在和hWnd窗口句柄对应的窗口以windows消息的形式接受网络事件的通知。

看窗口消息如何定义:

[cpp] view plaincopy
  1. LRESULT CALLBACK WindowProc(
  2. HWND hwnd,//一个窗口句柄,对窗口的调用就是由这个窗口发出的
  3. UINT uMsg,//指定需要对那些消息进行处理。
  4. WPARAM wParam,//指定在上面发生了一个网络事件的套接字。
  5. LPARAM lParam//低字节制定了已经发生的网络事件,高字节包含了可能出现的错误代码。
  6. );

来看一下步骤:当网络消息抵达窗口后,应用程序就会先检查lParam的高字节位,以判断是否是在网络错误。WSAGETSELECTERROR这个宏可返回高字节位包含的错误信息。

然后如果程序没有发现套接字上没产生错误,接着就要调查到底是那个网络事件类型,具体做法是读取lParam的低字节位。  WSAGETSELECTEVENT这个宏返回lParam的低字节部分。

看一下代码:

[cpp] view plaincopy
  1. #include<Windows.h>
  2. #include<tchar.h>
  3. #define MSGSIZE 1024
  4. #define WM_SOCKET WM_USER+100
  5. #pragma comment(lib, "ws2_32.lib")
  6. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  7. int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd )
  8. {
  9. TCHAR classname[] = "AsyncSelect";
  10. WNDCLASS wndclass;   //窗口类
  11. wndclass.style = CS_HREDRAW | CS_VREDRAW;//窗口类型
  12. wndclass.lpfnWndProc = WindowProc;//窗口处理函数
  13. wndclass.cbClsExtra = 0;//窗口类无扩展
  14. wndclass.cbWndExtra = 0;//窗口实例无扩展
  15. wndclass.hInstance = hInstance;//当前实例句柄
  16. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);//窗口最小化图标为缺省图标
  17. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);//窗口用箭头光标
  18. wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//窗口背景用白色
  19. wndclass.lpszMenuName = NULL;//窗口没有菜单
  20. wndclass.lpszClassName = classname;//窗口类名为“窗口”
  21. //注册窗口类
  22. if (!RegisterClass(&wndclass))
  23. {
  24. MessageBox(NULL, "register class error", classname, MB_ICONERROR);
  25. return 0;
  26. }
  27. //创建窗口(窗口类名,窗口标题,窗口风格,坐标缺省, 有没有父窗口,有没有子窗口, 创建这个窗口的应用程序当前句柄,不适用)
  28. HWND hwnd = CreateWindow(classname, "AsyncSelect Model", WS_OVERLAPPEDWINDOW,
  29. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  30. NULL, NULL, hInstance, NULL);
  31. //显示和更新
  32. ShowWindow(hwnd, nShowCmd);
  33. UpdateWindow(hwnd);
  34. MSG msg;
  35. //消息循环
  36. while (GetMessage(&msg, NULL, 0, 0))
  37. {
  38. TranslateMessage(&msg);
  39. DispatchMessage(&msg);
  40. }
  41. return msg.wParam;
  42. }
  43. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  44. {
  45. WSADATA wsd;
  46. static SOCKET slisten;
  47. SOCKET sClient;
  48. SOCKADDR_IN local, client;
  49. int ret, iAddrsize = sizeof(client);
  50. char szMessage[MSGSIZE] = {0};
  51. switch (uMsg)
  52. {
  53. case WM_DESTROY:
  54. {
  55. //退出清理
  56. closesocket(slisten);
  57. WSACleanup();
  58. PostQuitMessage(0);
  59. return 0;
  60. }
  61. case WM_CREATE:
  62. {
  63. //初始化
  64. WORD sockVersion = MAKEWORD(2, 0);
  65. WSAStartup(sockVersion, &wsd);
  66. //创建socket
  67. slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  68. local.sin_family = AF_INET;
  69. local.sin_port = htons(8888);
  70. local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
  71. //绑定socket
  72. if(bind(slisten, (sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
  73. {
  74. WSACleanup();
  75. return 0;
  76. }
  77. //监听socket
  78. if(listen(slisten, 5) == SOCKET_ERROR)
  79. {
  80. WSACleanup();
  81. return 0;
  82. }
  83. //注册监听socket FD_ACCEPT事件,当socket有连接时,会发送WM_SOCKET消息给窗口
  84. WSAAsyncSelect(slisten, hwnd, WM_SOCKET, FD_ACCEPT);
  85. return 0;
  86. }
  87. case WM_SOCKET:
  88. {
  89. if (WSAGETSELECTERROR(lParam))
  90. {
  91. closesocket(wParam);
  92. break;
  93. }
  94. switch(WSAGETSELECTEVENT(lParam))
  95. {
  96. case FD_ACCEPT:
  97. {
  98. //接受
  99. sClient = accept(wParam, (sockaddr*)&client, &iAddrsize);
  100. //注册客户socket FD_READ和FD_CLOSE事件
  101. WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ|FD_CLOSE);
  102. break;
  103. }
  104. case FD_READ:
  105. {
  106. //接受
  107. ret = recv(wParam, szMessage, MSGSIZE, 0);
  108. if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
  109. {
  110. closesocket(wParam);
  111. }
  112. else
  113. {
  114. //发送
  115. szMessage[ret] = '\0';
  116. send(wParam, szMessage, strlen(szMessage), 0);
  117. }
  118. break;
  119. }
  120. case FD_CLOSE:
  121. {
  122. closesocket(wParam);
  123. break;
  124. }
  125. default:
  126. {
  127. closesocket(wParam);
  128. break;
  129. }
  130. }
  131. }
  132. return 0;
  133. }
  134. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  135. }

2012/9/2

jofranks于南昌

版权声明:本文为博主原创文章,未经博主允许不得转载。

【网络编程】之八、异步选择WSAAsyncSelect相关推荐

  1. 二.Windows I/O模型之异步选择(WSAAsyncSelect)模型

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

  2. 异步选择WSAAsyncSelect

    大家用这个模型,可以让应用程序在一个套接字上接收以windows消息为基础的网络事件通知.我们想要用这个操作,具体的做法就是我们建立一个套接字,然后调用WSAAsyncSelect函数, 也就是说,这 ...

  3. python的异步网络编程_python异步网络编程怎么使socket关闭之后立即执行一段代码?...

    import socket from _socket import getdefaulttimeout class MySocket(socket.socket): """ ...

  4. 【网络编程】之五、异步模型

    注:本文部分转载 一:select模型 二:WSAAsyncSelect模型 三:WSAEventSelect模型 四:Overlapped I/O 事件通知模型 五:Overlapped I/O 完 ...

  5. Boost库网络编程

    Boost库网络编程和异步IO(一) boost::asio概要 boost::aiso主要用于跨平台网络开发,封装了底层常用的网络操作和同步.异步IO操作,可以很快速的设计开发出高并发网络服务程序. ...

  6. Python网络编程(4)——异步编程select epoll

    在SocketServer模块的学习中,我们了解了多线程和多进程简单Server的实现,使用多线程.多进程技术的服务端为每一个新的client连接创建一个新的进/线程,当client数量较多时,这种技 ...

  7. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)...

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程并行与并发同步与异步阻塞与非阻塞CPU密集型与IO密集型 线程与进程 进程 前言 ...

  8. linux网络编程tcp和udp基本函数调用过程及如何选择

    1. socket编程 1.1 概述 TCP是TCP/IP体系中面向连接的传输层协议,它提供全双工和可靠交付的服务.它采用许多机制来确保端到端结点之间的可靠数据传输,如采用序列号.确认重传.滑动窗口等 ...

  9. Python 异步网络编程实战

    Python 异步网络编程实战 - songcser - 掘金小册 小册介绍 第一部分是对 Python 协程的讲解,从字节码开始简单讲解了 Python 虚拟机的执行过程,可以大体了解到 Pytho ...

最新文章

  1. 数据结构(05)— 线性单链表实战
  2. 操作系统学习笔记 第四章:存储器管理(王道考研)
  3. 支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型
  4. Securing Session State
  5. 1SGD、Momention原理
  6. TextView 显示图像+文字的方法
  7. Java 基于 TCP/IP 实现 Socket中的多客户端通信
  8. ASP.NET Core 开源项目 nopCommerce,一款沉淀13年的电商开源佳作!
  9. (二)深入浅出TCPIP之再识TCP,理解TCP三次握手(上)
  10. Java笔试题解答和部分面试题
  11. 深入理解Java反射+动态代理,java开发面试笔试题
  12. 隐藏java_Java方法隐藏
  13. IDEA搭建一个简单的Javaweb项目(二)
  14. ZooKeeper 了解
  15. AcWing 828. 模拟栈
  16. 16.进程间的通信:管道
  17. 几种调用WebService的方法
  18. DL实战(3):cfNet- Matlab配置
  19. Windows内核学习------双机调试的安装(物理机win10,虚拟机win7,虚拟机软件vmware)
  20. PCI-E 1x, 4x, 8x, 16x 接口定义

热门文章

  1. Zuul使用正则表达式指定路由规则
  2. SpringBoot_配置-@Conditional自动配置报告
  3. Disruptor并发框架-2
  4. 骁龙660_高通骁龙660可以带动6g运行内存吗?
  5. java bean传索引_Java如何设置bean的索引属性值?
  6. b站2020用户画像_B站2020年度动画大选来袭!论引战,还是要看B站!
  7. JavaScript正则表达式语法与示例
  8. C# Directory.Exists() 文件存在但返回一直为false
  9. 用css3实现ps蒙版效果+动画
  10. 26.删除排序数组中的重复项