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:
    1. When WSAAsyncSelect is called, if there is data currently available to receive.   ------ WSAAsyncSelect 调用后,新的数据等待接收。
    2. When data arrives, if FD_READ is not already posted. ------   新的数据到达,而FD_READ 还没有传递。
    3. 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:
    1. When WSAAsyncSelect called, if a send or sendto is possible.  ----- WSAAsyncSelect调用的时候
    2. After connect or accept called, when connection established.  ----- connect或accept调用的时候,新连接到达时进入
    3. After send or sendto fail with WSAEWOULDBLOCK, when send or sendto are likely to succeed.  ----- send等函数发送数据,但缓冲区满了,部分数据未能及时发送出去,此时将产生 WSAEWOULDBLOCK错误码。此后,系统将产生该事件,通知用户重新发送数据。
    4. 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).
    1. When WSAAsyncSelect called, if there is OOB data currently available to receive with the MSG_OOB flag.
    2. When OOB data arrives, if FD_OOB not already posted.
    3. After recv or recvfrom called with or without MSG_OOB flag, if OOB data is still available to receive.
  • FD_ACCEPT:
    1. When WSAAsyncSelect called, if there is currently a connection request available to accept. ----- WSAAsyncSelect 调用后,有连接请求等待accept
    2. When a connection request arrives, if FD_ACCEPT not already posted.
    3. After accept called, if there is another connection request available to accept. ----- accept连接后,另外有一个连接等待accept
  • FD_CONNECT:
    1. When WSAAsyncSelect called, if there is currently a connection established.----- WSAAsyncSelect 调用后,有连接建立时。
    2. After connect called, when connection is established, even when connect succeeds immediately, as is typical with a datagram socket.
    3. After calling WSAJoinLeaf, when join operation completes.
    4. 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)
    1. When WSAAsyncSelect called, if socket connection has been closed.  ----- 连接关闭时进入
    2. 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).
    3. 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.
    4. 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:
    1. When WSAAsyncSelect called, if the quality of service associated with the socket has been changed.
    2. 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模型的更多相关文章

  1. winsock编程WSAEventSelect模型

    winsock编程WSAEventSelect模型 WSAEventSelect模型和WSAAsyncSelec模型类似,都是用调用WSAXXXXXSelec函数将socket和事件关联并注册到系统, ...

  2. winsock编程IOCP模型实现代码

    winsock编程IOCP模型实现代码 话不多说,上代码.借鉴<windows核心编程>部分源码和CSDN小猪部分代码. stdafx.h依赖头文件: #include <iostr ...

  3. winsock编程select模型

    winsock编程select模型 网络服务端连接数量过多时,为每一个连接申请一个线程会让机器性能急剧下降(大多说是因为线程在用户态和内核态之间切换会占用大量的CPU时间片).为了解决多线程带来的性能 ...

  4. 问题解决——WSAAsyncSelect模型 不触发 FD_CLOSE

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  5. Winsock编程基础介绍 .

    相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API. 使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Win ...

  6. WSAAsyncSelect 模型

    WSAAsyncSelect模型是winsock编程模型的一种,它提供了socket异步编程的方便,其实现是基于Windows消息机制的,最主要的就是下面这个函数: int PASCAL FAR WS ...

  7. WinSock 重叠IO模型

    title: WinSock 重叠IO模型 tags: [WinSock 模型, 网络编程, 重叠IO模型] date: 2018-06-29 20:26:13 categories: Windows ...

  8. WSAAsyncSelect模型

    ============================================== █ 异步选择(WSAAsyncSelect)模型是一个有用的异步 I/O 模型.利用这个模型,应用程序可在 ...

  9. winsock I/O模型的分析

    几种winsock I/O模型的分析 套接字是通信的基础,是支持网络协议数据通信的基本接口.Winsocket 提供了一些有趣的I/O模型,有助于应用程序通过一种“异步”方式,一次对一个或者多个套接字 ...

随机推荐

  1. JQuery笔记(三)选项卡

    通过jq封装的方法,可以更简单的制作一个选项卡 <!DOCTYPE html> <html lang="en"> <head> <meta ...

  2. 什么是Bash Shell的内建(build in)命令

    1.什么是build in命令: shell内建命令是指bash(或其它版本)工具集中的命令.一般都会有一个与之同名的系统命令,比如bash中的echo命令与/bin/echo是两个不同的命令,尽管他 ...

  3. [WPF] 为Style 里的button添加鼠标点击响应事件

    一个TabControl, 用的是PagedTabControl style, 在style中有个button, button在style里已经写了click事件,但是现在还需要加上一段功能,就是在响 ...

  4. sudo命令出错 must set be suid

    特殊权限 4,2 ,1 4  suid,控制用户执行的文件,以文件所属用户的身份执行.当一个可执行的文件拥有suid时,会将文件拥有者的x位变成s(---s--x--x),这时称为set uid,简写 ...

  5. 理解iaas paas saas三种云服务区别

    其实搞懂这个问题也不难,我们可以把云计算理解成一栋大楼,而这栋楼又可以分为顶楼.中间.低层三大块.那么我们就可以把Iass(基础设施).Pass(平台).Sass(软件)理解成这栋楼的三部分.基础设施 ...

  6. react总结

    在我的工作用到的最多就是backbone,其次还会有ember/Ext,backbone目前能实现我们team所需要实现的功能,因为我们的component不需要频繁的操作Dom,当后台API返回数据 ...

  7. perl-Thread-Queue for openwrt

    在centos7下运行 openwrt trunk的时候提示需要perl-thread-queue. yum install perl-thread-queue,提示没有这个文件.百度和google, ...

  8. HTML5入门总结 HTML5API

    w3cshools  MDN英文  MDN中文 HTML5 HTML5 is the latest evolution of the standard that defines HTML. The t ...

  9. Activity的生命周期和启动模式

    Activity的生命周期分析 典型情况下的生命周期.是指在用户参与的情况下,Activity所经过的生命周期的改变. 异常情况下的生命周期.是指Activity被系统回收或者由于当前设备的Confi ...

  10. android 5.0 -- Ripple 效果

    Ripple 水波纹效果,也就是涟漪效果. 波纹效果有两种: 1,波纹有边界:波纹涟漪效果只是显示在控件内部 android:background="?android:attr/select ...