winsock编程WSAAsyncSelect模型
winsock编程WSAAsyncSelect模型
WSAAsyncSelect模型也称异步选择模型,其核心函数是WSAAsyncSelect。它可以用来在一个socket上接收以windows消息为基础的网络事件。它提供了读写数据的异步通知功能,但不提供异步数据传送。WSAAsyncSelect模型的优势在于只需要一个主线程即可。缺点是必须要绑定窗口句柄。
1:WSAAsyncSelect函数定义
Description:The WSAAsyncSelect function requests Windows message-based notification of network events for a socket.
int WSAAsyncSelect(
__in SOCKET s,
__in HWND hWnd,
__in unsigned int wMsg,
__in long lEvent
);
Parameters
- s
-
A descriptor that identifies the socket for which event notification is required.
- hWnd
-
A handle that identifies the window that will receive a message when a network event occurs.
接收网络事件消息的窗口句柄
- wMsg
-
A message to be received when a network event occurs.
网络事件消息
- lEvent
-
A bitmask that specifies a combination of network events in which the application is interested.
网络事件,windows已定义好网络事件,如FD_CONNECT、FD_CLOSE、FD_ACCEPT等。
Return Value
If the WSAAsyncSelect function succeeds, the return value is zero, provided that the application's declaration of interest in the network event set was successful. Otherwise, the value SOCKET_ERROR is returned, and a specific error number can be retrieved by calling WSAGetLastError.
2:网络事件说明
MSDN上列出如下常见网络事件:

MSDN对上述网络事件及关联函数触发关系的解释如下:
Here is a summary of events and conditions for each asynchronous notification message.
- FD_READ:
- When WSAAsyncSelect is called, if there is data currently available to receive. ------ WSAAsyncSelect 调用后,新的数据等待接收。
- When data arrives, if FD_READ is not already posted. ------ 新的数据到达,而FD_READ 还没有传递。
- After recv or recvfrom is called, with or without MSG_PEEK), if data is still available to receive. ----- 使用recv等函数后,仍有数据等待接收。MSG_PEEK解释:MSG_PEEK可作为recv等函数最后一个参数的标志位传入。如果recv带有MSG_PEEK,则recv读取数据后,并不会把数据从缓冲区取出来,这样可以方便其他recv调用方继续读取缓冲区数据。如果recv不带有MSG_PEEK,recv读取一定长度数据后,缓冲区将移除该部分数据。
Note When setsockopt SO_OOBINLINE is enabled, data includes both normal data and OOB data in the instances noted above.
- FD_WRITE:
- When WSAAsyncSelect called, if a send or sendto is possible. ----- WSAAsyncSelect调用的时候
- After connect or accept called, when connection established. ----- connect或accept调用的时候,新连接到达时进入
- After send or sendto fail with WSAEWOULDBLOCK, when send or sendto are likely to succeed. ----- send等函数发送数据,但缓冲区满了,部分数据未能及时发送出去,此时将产生 WSAEWOULDBLOCK错误码。此后,系统将产生该事件,通知用户重新发送数据。
- After bind on a connectionless socket. FD_WRITE may or may not occur at this time (implementation-dependent). In any case, a connectionless socket is always writeable immediately after a bind operation.
- FD_OOB: Only valid when setsockopt SO_OOBINLINE is disabled (default).
- FD_ACCEPT:
- When WSAAsyncSelect called, if there is currently a connection request available to accept. ----- WSAAsyncSelect 调用后,有连接请求等待accept
- When a connection request arrives, if FD_ACCEPT not already posted.
- After accept called, if there is another connection request available to accept. ----- accept连接后,另外有一个连接等待accept
- FD_CONNECT:
- When WSAAsyncSelect called, if there is currently a connection established.----- WSAAsyncSelect 调用后,有连接建立时。
- After connect called, when connection is established, even when connect succeeds immediately, as is typical with a datagram socket.
- After calling WSAJoinLeaf, when join operation completes.
- After connect, WSAConnect, or WSAJoinLeaf was called with a nonblocking, connection-oriented socket. The initial operation returned with a specific error of WSAEWOULDBLOCK, but the network operation went ahead. Whether the operation eventually succeeds or not, when the outcome has been determined, FD_CONNECT happens. The client should check the error code to determine whether the outcome was successful or failed.
- FD_CLOSE: Only valid on connection-oriented sockets (for example, SOCK_STREAM)
- When WSAAsyncSelect called, if socket connection has been closed. ----- 连接关闭时进入
- After remote system initiated graceful close, when no data currently available to receive (Be aware that, if data has been received and is waiting to be read when the remote system initiates a graceful close, the FD_CLOSE is not delivered until all pending data has been read).
- After local system initiates graceful close with shutdown and remote system has responded with "End of Data" notification (for example, TCP FIN), when no data currently available to receive.
- When remote system terminates connection (for example, sent TCP RST), and lParam will contain WSAECONNRESET error value.
Note FD_CLOSE is not posted after closesocket is called.---- 获取FD_CLOS后应调用closesocket
- FD_QOS:
- When WSAAsyncSelect called, if the quality of service associated with the socket has been changed.
- After WSAIoctl with SIO_GET_QOS called, when the quality of service is changed.
- FD_GROUP_QOS: Reserved.
- FD_ROUTING_INTERFACE_CHANGE:
- After WSAIoctl with SIO_ROUTING_INTERFACE_CHANGE called, when the local interface that should be used to reach the destination specified in the IOCTL changes.
- FD_ADDRESS_LIST_CHANGE:
- After WSAIoctl with SIO_ADDRESS_LIST_CHANGE called, when the list of local addresses to which the application can bind changes.
连续调用两次WSAAsyncSelect函数,后设置的事件标志位将替换先前设置的事件标志位。设置多重事件,需要用到或运算,如FD_READ|FD_WRITE。
3:自定义消息传参
The wParam parameter identifies the socket on which a network event has occurred. The low word of lParam specifies the network event that has occurred. The high word of lParam contains any error code. The error code be any error as defined in Winsock2.h.
WSAGETSELECTEVENT和WSAGETSELECTERROR宏
Description:The error and event codes can be extracted from the lParam using the macros WSAGETSELECTERROR and WSAGETSELECTEVENT, defined in Winsock2.h as:
#define WSAGETSELECTERROR(lParam) HIWORD(lParam)
#define WSAGETSELECTEVENT(lParam) LOWORD(lParam)
自定义消息函数的传递参数中,wParam 标识socket描述符。lParam 的低字节标识了网络事件,lParam 的高字节标识了错误码。分别用WSAGETSELECTEVENT和WSAGETSELECTERROR可以取出lparam内的网络事件和错误码。
4:测试程序
WSAAsyncSelect 传参需要窗口句柄,为了简化代码,我直接创建了一个mfc对话框程序,用m_hwnd给WSAAsyncSelect 传参。对话框类名为WSAAsyncSelecDlg。
A:定义变量
bool m_bRes; //用作socket流程各函数调用依据
WSAData m_wsa; //wsastartup参数
SOCKET m_listensocket; //监听socket
B:定义消息宏及消息映射函数
#define WM_SOCK WM_USER+1 afx_msg LRESULT OnSocket(WPARAM w,LPARAM l); ON_MESSAGE(WM_SOCK,OnSocket)
C:在OnInitDialog内创建监听socket
m_bRes = true;
WSAStartup(MAKEWORD(,),&m_wsa);
m_listensocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (m_listensocket == INVALID_SOCKET )
{
m_bRes = false;
}
sockaddr_in m_server;
m_server.sin_family = AF_INET;
m_server.sin_port = htons();
m_server.sin_addr.s_addr = inet_addr("127.0.0.1");
if (m_bRes && (bind(m_listensocket,(sockaddr*)&m_server,sizeof(sockaddr_in)) == SOCKET_ERROR))
{
DWORD dw = WSAGetLastError();
m_bRes = false;
}
if (m_bRes && (listen(m_listensocket,SOMAXCONN) == SOCKET_ERROR))
{
m_bRes = false;
}
if (m_bRes && (WSAAsyncSelect(m_listensocket,m_hWnd,WM_SOCK,FD_ACCEPT) == SOCKET_ERROR))
{
m_bRes = false;
}
D:实现消息映射函数
LRESULT CWSAAsyncSelecDlg::OnSocket(WPARAM w,LPARAM l)
{
SOCKET s = (SOCKET)w;
switch (WSAGETSELECTEVENT(l))
{
case FD_ACCEPT:
{//有网络连接到达
sockaddr_in m_client;
int sz = sizeof(sockaddr_in);
SOCKET acp = accept(m_listensocket,(sockaddr*)&m_client,&sz);
if (acp == INVALID_SOCKET)
{
closesocket(m_listensocket);
return ;
}
WSAAsyncSelect(acp,m_hWnd,WM_SOCK,FD_READ|FD_WRITE|FD_CLOSE);
}
break;
case FD_READ:
{//缓冲区有数据待接收时进入
char buf[];
int res = recv(s,buf,,);
if (res == )
{
closesocket(s);
break;
}
else if (res == SOCKET_ERROR)
{
//socket error
break;
}
else
{
buf[res] = ;
std::string str = buf;
str += "\n";
OutputDebugString(str.c_str());
str = "WSAAsyncSelect test";
int res = send(s,str.c_str(),str.length(),);
if (res == SOCKET_ERROR)
{
break;
}
}
}
break;
case FD_WRITE:
{//1:新连接到达时进入 2:缓冲区满数据未发送完全时进入
std::string str = "WSAAsyncSelect test";
int res = send(s,str.c_str(),str.length(),);
if (res == SOCKET_ERROR)
{
break;
}
}
break;
case FD_CLOSE:
{//客户端关闭连接时进入
closesocket(s);
}
break;
}
return ;
}
E:测试结果

客户端程序用的是http://www.cnblogs.com/hgwang/p/6086237.html里面的代码。
winsock编程WSAAsyncSelect模型的更多相关文章
- winsock编程WSAEventSelect模型
winsock编程WSAEventSelect模型 WSAEventSelect模型和WSAAsyncSelec模型类似,都是用调用WSAXXXXXSelec函数将socket和事件关联并注册到系统, ...
- winsock编程IOCP模型实现代码
winsock编程IOCP模型实现代码 话不多说,上代码.借鉴<windows核心编程>部分源码和CSDN小猪部分代码. stdafx.h依赖头文件: #include <iostr ...
- winsock编程select模型
winsock编程select模型 网络服务端连接数量过多时,为每一个连接申请一个线程会让机器性能急剧下降(大多说是因为线程在用户态和内核态之间切换会占用大量的CPU时间片).为了解决多线程带来的性能 ...
- 问题解决——WSAAsyncSelect模型 不触发 FD_CLOSE
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- Winsock编程基础介绍 .
相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API. 使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Win ...
- WSAAsyncSelect 模型
WSAAsyncSelect模型是winsock编程模型的一种,它提供了socket异步编程的方便,其实现是基于Windows消息机制的,最主要的就是下面这个函数: int PASCAL FAR WS ...
- WinSock 重叠IO模型
title: WinSock 重叠IO模型 tags: [WinSock 模型, 网络编程, 重叠IO模型] date: 2018-06-29 20:26:13 categories: Windows ...
- WSAAsyncSelect模型
============================================== █ 异步选择(WSAAsyncSelect)模型是一个有用的异步 I/O 模型.利用这个模型,应用程序可在 ...
- winsock I/O模型的分析
几种winsock I/O模型的分析 套接字是通信的基础,是支持网络协议数据通信的基本接口.Winsocket 提供了一些有趣的I/O模型,有助于应用程序通过一种“异步”方式,一次对一个或者多个套接字 ...
随机推荐
- 利用requestjs优化响应式移动端js加载
html: <script data-main="main" src="require.js"></script> main.js re ...
- jsp或servlet返回并刷新页面
2012-04-27 22:39:05| 分类: JAVA | 标签:返回刷新 |举报|字号 订阅 只用window.history.back(-1);返回页面但不会刷新,还是原来的数据 ...
- 关于UI_USER_INTERFACE_IDIOM() & UIDevice.model
使用 UI_USER_INTERFACE_IDIOM() 进行区分 (ios 3.2 >=) 无法区分iphone和ipod if (UI_USER_INTERFACE_IDIOM() == U ...
- Python基础(十一)-面向对象
三种编程范式: 1.函数式编程:函数指数学意义上的函数 由于命令式编程语言也可以通过类似函数指针的方式来实现高阶函数,函数式的最主要的好处主要是不可变性带来的.没有可变的状态,函数就是引用透明(Ref ...
- SQL in优化将In转化为联合查询
in查询有时候会非常影响性能,最好能转化为联合查询,但有的网友说sqlserver会自动将in转化为联合查询,但我实际遇到的有时候却不是这样.所以最好还是不要用in. 我自己的例子,用in的时候耗费了 ...
- foreach 循环的应用传值
$arr=array(1,5,8,8,9);foreach ($arr as $key => $value) { //这里可以一边改外面$arr的值一边下一步循环 $value=++$value ...
- centos7,yum安装的redis用systemctl无法启动
因为之前使用显示命令启动redis的,要使redis在后台运行就需要改redis.conf中的daemonize 为yes. 这次在centos7上也顺手改了为yes,然后使用systemctl启动, ...
- 异步设备IO:OVERLAPPED和IOCompletionPort
异步设备IO:OVERLAPPED和IOCompletionPort 本文内容为<windows核心编程>第10章内容的总结,仅记录一些本人感兴趣的内容. 1:OVERLAPPED &qu ...
- Asp.Net MVC2.0 Url 路由入门---实例篇
本篇主要讲述Routing组件的作用,以及举几个实例来学习Asp.Net MVC2.0 Url路由技术. 接着上一篇开始讲,我们在Global.asax中注册一条路由后,我们的请求是怎么转到相应的Vi ...
- $.ajax({})方法success,error,complete,beforeSend使用例子及解释
在与后台交互的时候,经常使用到jquery的$.ajax()方法来请求数据: 回调函数用的比较多的是success,但是complete.beforeSend.error函数也是很有用的: 下面是使用 ...