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模型,有助于应用程序通过一种“异步”方式,一次对一个或者多个套接字 ...
随机推荐
- requests模拟登录
#coding:utf-8 #author:jwong import requests import urllib2 import re from bs4 import BeautifulSoup a ...
- 【angular】angular如何让传递变量参数+ng-change的使用
HTML: <div class="form-group"> <label class="col-sm-2 control-label"> ...
- Mac最好的虚拟机软件Parallels,体验比Vmware棒
每一位Mac电脑用户,必须安装虚拟机软件,在虚拟机里面安装Windows系统,解决日常必须用windows软件的问题,解决国内网银登录的兼容问题. 你一定不要用Mac系统自带的boot camp方式安 ...
- .net通过WCF调用java发布的服务,获取数据
功能描述 java作为后台,连接数据库获取数据,然后发布SOAP services,让.net平台通过WCF进行引用. 实现步骤 1.在项目特定文件夹下,右键->添加服务引用,输入服务的url地 ...
- php curl 抓取内容
<?php$ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url)//抓取url curl_setopt($ch,CURLOPT_RETURNTRAN ...
- iframe自适应高度计算,iframe自适应
计算页面的实际高度,iframe自适应会用到 IfrHeight: function (iframeId, callback) { var height; function calcPageHeigh ...
- javascript 延时执行函数
延时执行函数,貌似有些多此一举, 也许还是有点用 记在这儿 var test = { delay : function(lifetime){ var data; setTimeout(function ...
- YII学习第二十三天,accessRules用法
访问控制过滤器(Access Control Filter)访问控制过滤器是检查当前用户是否能执行访问的controller action的初步授权模式. 这种授权模式基于用户名,客户IP地址和访问类 ...
- c语言正则表达式
标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一功能,其中最著名的当数Philip Hazel的Perl-Compatible Regular Expression库 ...
- 玩玩RMI
今天在看代理设计模式,java中远程代理的实现一定会用到RMI的,很久没有温习过RMI的知识了,今天就重新过一遍这个知识点来让自己加深印象,构建一个简单的RMI小程序需要用到一下几个类: java.r ...