异步选择WSAAsyncSelect
大家用这个模型,可以让应用程序在一个套接字上接收以windows消息为基础的网络事件通知。我们想要用这个操作,具体的做法就是我们建立一个套接字,然后调用WSAAsyncSelect函数, 也就是说,这个模型的核心就是我们的这个函数;
来看一下函数原型:
- int WSAAsyncSelect(
- _In_ SOCKET s,//我们感兴趣的套接字
- _In_ HWND hWnd,//窗口的句柄,对于网络事件繁盛后,想要接收到的通知的那个窗口
- _In_ unsigned int wMsg,//指定在发生网络事件时,打算接收的消息。
- _In_ long lEvent//指定一个位掩码,对应于一系列网络事件的组合。
- );
对于最后一个参数,在这里要说一下,他包括的网络事件模型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE。
到底使用FD_ACCEPT,还是使用FD_CONNECT类型,要取决于应用程序的身份是客户端,还是服务器。我们可以用或运算来一起使用;
FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据
FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据
FD_ACCEPT 应用程序想接收与进入连接有关的通知
FD_CONNECT 应用程序想接收与一次连接完成的通知
FD_CLOSE 应用程序想接收与套接字关闭的通知
实例:
- WSAAsyncSeltct(s, hwnd, WM_SOCKET, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);
应用程序可以在套接字s上,接收到有关连接,发送,接收以及套接字关闭的一系列通知了。
要注意的是:通过上面的函数原型我们可以看出来,要想使用我们的这个模型,必须要先调用CreateWindow函数来创建一个窗口,然后再为窗口提供一个窗口例程函数(WinProc);
这里要说的注意是:
当你有多个事件的时候,你一定要在套接字上一次注册,一旦你在这个套接字上允许了事件通知,那么以后除非你明确的调用closesocket命令或者由应用程序针对的那个套接字调用了WSAAsyncSelect,那么你就更改了注册的网络事件的类型了,否则的话事件通知就会永远有效。 上面函数你最后一个参数设置为0,效果相当于你停止在套接字上进行的所有网络事件通知。
还有就是你的应用程序针对一个套接字调用了WSAAsyncSelect,那么套接字会从“锁定”模式变成“非锁定”模式。 这样以后,会导致错误。 为了防止错误的产生,应用程序依赖于由WSAAsyncSelect的第三个参数指定的用户自定义窗口消息,来判断网络事件类型何时在套接字上发生,不能盲目的调用。
当你的程序调用WSAAsyncSelect成功后,会在和hWnd窗口句柄对应的窗口以windows消息的形式接受网络事件的通知。
看窗口消息如何定义:
- LRESULT CALLBACK WindowProc(
- HWND hwnd,//一个窗口句柄,对窗口的调用就是由这个窗口发出的
- UINT uMsg,//指定需要对那些消息进行处理。
- WPARAM wParam,//指定在上面发生了一个网络事件的套接字。
- LPARAM lParam//低字节制定了已经发生的网络事件,高字节包含了可能出现的错误代码。
- );
来看一下步骤:当网络消息抵达窗口后,应用程序就会先检查lParam的高字节位,以判断是否是在网络错误。WSAGETSELECTERROR这个宏可返回高字节位包含的错误信息。
然后如果程序没有发现套接字上没产生错误,接着就要调查到底是那个网络事件类型,具体做法是读取lParam的低字节位。 WSAGETSELECTEVENT这个宏返回lParam的低字节部分。
看一下代码:
- #include<Windows.h>
- #include<tchar.h>
- #define MSGSIZE 1024
- #define WM_SOCKET WM_USER+100
- #pragma comment(lib, "ws2_32.lib")
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd )
- {
- TCHAR classname[] = "AsyncSelect";
- WNDCLASS wndclass; //窗口类
- wndclass.style = CS_HREDRAW | CS_VREDRAW;//窗口类型
- wndclass.lpfnWndProc = WindowProc;//窗口处理函数
- 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 = classname;//窗口类名为“窗口”
- //注册窗口类
- if (!RegisterClass(&wndclass))
- {
- MessageBox(NULL, "register class error", classname, MB_ICONERROR);
- return 0;
- }
- //创建窗口(窗口类名,窗口标题,窗口风格,坐标缺省, 有没有父窗口,有没有子窗口, 创建这个窗口的应用程序当前句柄,不适用)
- HWND hwnd = CreateWindow(classname, "AsyncSelect Model", WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- NULL, NULL, hInstance, NULL);
- //显示和更新
- ShowWindow(hwnd, nShowCmd);
- UpdateWindow(hwnd);
- MSG msg;
- //消息循环
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return msg.wParam;
- }
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- WSADATA wsd;
- static SOCKET slisten;
- SOCKET sClient;
- SOCKADDR_IN local, client;
- int ret, iAddrsize = sizeof(client);
- char szMessage[MSGSIZE] = {0};
- switch (uMsg)
- {
- case WM_DESTROY:
- {
- //退出清理
- closesocket(slisten);
- WSACleanup();
- PostQuitMessage(0);
- return 0;
- }
- case WM_CREATE:
- {
- //初始化
- WORD sockVersion = MAKEWORD(2, 0);
- WSAStartup(sockVersion, &wsd);
- //创建socket
- slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- local.sin_family = AF_INET;
- local.sin_port = htons(8888);
- local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
- //绑定socket
- if(bind(slisten, (sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
- {
- WSACleanup();
- return 0;
- }
- //监听socket
- if(listen(slisten, 5) == SOCKET_ERROR)
- {
- WSACleanup();
- return 0;
- }
- //注册监听socket FD_ACCEPT事件,当socket有连接时,会发送WM_SOCKET消息给窗口
- WSAAsyncSelect(slisten, hwnd, WM_SOCKET, FD_ACCEPT);
- return 0;
- }
- case WM_SOCKET:
- {
- if (WSAGETSELECTERROR(lParam))
- {
- closesocket(wParam);
- break;
- }
- switch(WSAGETSELECTEVENT(lParam))
- {
- case FD_ACCEPT:
- {
- //接受
- sClient = accept(wParam, (sockaddr*)&client, &iAddrsize);
- //注册客户socket FD_READ和FD_CLOSE事件
- 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;
- }
- default:
- {
- closesocket(wParam);
- break;
- }
- }
- }
- return 0;
- }
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
2012/9/2
jofranks于南昌
异步选择WSAAsyncSelect相关推荐
- 二.Windows I/O模型之异步选择(WSAAsyncSelect)模型
1.基于windows消息为基础的网络事件io模型.因此我们必须要在窗口程序中使用该模型.该模型中的核心是调用WSAAsyncSelect函数实现异步I/O. 2.WSAAsyncSelect函数:注 ...
- 【网络编程】之八、异步选择WSAAsyncSelect
大家用这个模型,可以让应用程序在一个套接字上接收以windows消息为基础的网络事件通知.我们想要用这个操作,具体的做法就是我们建立一个套接字,然后调用WSAAsyncSelect函数, 也就是说,这 ...
- TCP/IP网络模型之异步选择模型
异步选择模型是基于窗口实现 窗口的创建如下: 1.创建窗口结构体 typedef struct tagWNDCLASSEXW {UINT cbSize;UINT style;WNDPROC lpfnW ...
- TCP流式套接字的异步事件WSAAsyncSelect编程
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! WSAA ...
- select模型使用例子
在windows平台构建网络应用,必须了解socket I/O模型.windows提供了选择(select).异步选择(WSAAsyncSelect).事件选择(WSAEventSelect).重叠I ...
- [WinSock]封装WSAAsyncSelect!
封装目标: 最终目标是封装WinSock的WSAAsyncSelect IO模型. 封装原则: 耦合性[减少各种依赖,包括classes之间,编译模块之间.],小粒度增加可复用性. 依赖ATL/WTL ...
- WinSock三种选择I/O模型
在<套接字socket及C/S通信的基本概念>和<WinSock编程基础>中,我们介绍了套接字的基本概念和WinSock API的基本调用规范.我们讨论了阻塞模式/非阻塞模式和 ...
- 孙鑫MFC笔记之十四--多线程同步与异步套接字编程
线程同步有三种方式: 1. 互斥对象涉及方法: HANDLE hMutex=CreateMutex(NULL,FALSE,NULL); //第二个参数为FALSE,将互斥对象声明为空闲状态 ...
- 异步SOCKET与同步SOCKET
阻塞与非阻塞SOCKET Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞.在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程 ...
最新文章
- C++ map详细介绍
- 彻底搞懂 Git-Rebase
- BSP细分时代即将来临
- C++(1) 指针 new 和delete
- 《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制
- 快过年了,分享 25 个 JS 实用技巧送给大家吧
- ArcGIS API For JavaScript——空间查询(FindTask和IdentifyTask)
- 电信商务领航1-1端口映射即虚拟服务器
- Java单例模式——线程安全的懒汉模式
- python实现素数判断
- 计算机主板常见故障检修,主板常见故障检查与维修
- 应用之星教你制作高下载量的App
- Ubuntu 测网速
- 如何使用百度baidu对某个特定网站进行站内搜索/检索
- 解密韦德之膝:康复因再世华佗
- 【Python网络爬虫】基本原理
- 使用调试钩子屏蔽全局钩子
- C语言:求高次方数的尾数
- Laradock 使用笔记
- Cython配置安装(ubuntu)
热门文章
- Linux指令设置波特率停止位,linux下的picocom怎么设置停止位,波特率
- 日期类型前后台传递格式控制注解@DateTimeFormat@JsonFormat@JSONField
- 用几何语言表示线段ab的中点c,做完这30道精选题,你的几何图形绝对满分!
- MYSQL执行计划EXPLAIN
- 解决Fast api打印两次日志的问题
- python使用xlwt创建与保存excel文件
- 自动初始化 git Bash脚本
- java tlv格式_java解析TLV格式数据
- 回声检测仿真信号matlab,杭州oracle培训入门
- 每周学算法/读英文/知识点心得分享 3.4 - 3.8