异步选择(WSAAsyncSelect)模型是一个有用的异步I/O 模型。其核心函数是WSAAsyncSelect,该函数是非阻塞的

(关于异步io的理解详情可以看:http://www.cnblogs.com/curo0119/p/8461520.html

它可以用来在一个socket上接收以windows消息为基础的网络事件。它提供了读写数据的异步通知功能,但不提供异步数据传送。WSAAsyncSelect模型的优势在于只需要一个主线程即可。缺点是必须要绑定窗口句柄。即要先调用createwindow创建一个窗口。这也就是为什么这个模型只适用于windows操作系统而不能跨平台的原因。

WSAAsyncSelect 的函数原型如下:

int WSAAsyncSelect( 

__in         SOCKET s,

__in         HWND hWnd,

__in         unsigned int wMsg,

__in         long lEvent

);

s 参数指定的是我们感兴趣的那个套接字。

● hWnd 参数指定一个窗口句柄,它对应于网络事件发生之后,想要收到通知消息的那个窗口。

● wMsg 参数指定在发生网络事件时,打算接收的消息。该消息会投递到由hWnd窗口句柄指定的那个窗口。

(通常,应用程序需要将这个消息设为比Windows的WM_USER大的一个值,避免网络窗口消息与系统预定义的标准窗口消息发生混淆与冲突)

(即自定义消息)

● lEvent 参数指定一个位掩码,对应于一系列网络事件的组合,大多数应用程序通常感兴趣的网络事件类型包括:

FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE。当然,到底使用FD_ACCEPT,还是使用FD_CONNECT类型,

要取决于应用程序的身份是客户端,还是服务器。如应用程序同时对多个网络事件有兴趣,只需对各种类型执行一次简单的按位OR(或)运算,

然后将它们分配给lEvent就可以了,例如:

WSAAsyncSeltct(s, hwnd,WM_SOCKET, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);

解释说明:我们的应用程序以后便可在套接字s上,接收到有关连接、发送、接收以及套接字关闭这一系列网络事件的通知。

FD_READ       应用程序想要接收有关是否可读的通知,以便读入数据

FD_WRITE   应用程序想要接收有关是否可写的通知,以便写入数据

FD_ACCEPT     应用程序想接收与进入连接有关的通知

FD_CONNECT 应用程序想接收与一次连接完成的通知

FD_CLOSE   应用程序想接收与套接字关闭的通知

█ 注意 ①:

多个事件务必在套接字上一次注册!

另外还要注意的是,一旦在某个套接字上允许了事件通知,那么以后除非明确调用closesocket命令,

或者由应用程序针对那个套接字调用了WSAAsyncSelect,从而更改了注册的网络事件类型,否则的话,

事件通知会永远有效!若将lEvent参数设为0,效果相当于停止在套接字上进行的所有网络事件通知。

█ 注意 ②:

若应用程序针对一个套接字调用了WSAAsyncSelect,那么套接字的模式会自动从“阻塞”变成“非阻塞”。

这样一来,如果调用了像WSARecv这样的Winsock函数,但当时却并没有数据可用,那么必然会造成调用的失败,并返回WSAEWOULDBLOCK错误。

为防止这一点,应用程序应依赖于由WSAAsyncSelect的uMsg参数指定的用户自定义窗口消息,来判断网络事件类型何时在套接字上发生;而不应盲目地进行调用。

应用程序在一个套接字上成功调用了WSAAsyncSelect之后,会在与hWnd窗口句柄对应的窗口类中,以Windows消息的形式,接收网络事件通知。

窗口例程通常定义如下:

LRESULT CALLBACK WindowProc(

HWND hwnd,

UINT uMsg,

WPARAM wParam,

LPARAM lParam

);

● hWnd 参数指定一个窗口的句柄,对窗口例程的调用正是由那个窗口发出的。

● uMsg 参数指定需要对哪些消息进行处理。这里我们感兴趣的是WSAAsyncSelect调用中定义的消息。

● wParam 参数指定发生网络事件的socket。假若同时为这个窗口例程分配了多个套接字,这个参数的重要性便显示出来了。

● lParam参数中,包含了两方面重要的信息。其中,lParam的低字(低位字)指定了已经发生的网络事件,而lParam的高字(高位字)包含了可能出现的任何错误代码。

█ 步骤:网络事件消息抵达一个窗口例程后,应用程序首先应检查lParam的高字位,以判断是否在网络错误。

这里有一个特殊的宏: WSAGETSELECTERROR,可用它返回高字位包含的错误信息。

若应用程序发现套接字上没有产生任何错误,接着便应调查到底是哪个网络事件类型,具体的做法便是读取lParam低字位的内容。

此时可使用另一个特殊的宏:WSAGETSELECTEVENT,用它返回lParam的低字部分(也就是FD_)。

如:

if(WSAGETSELECTERROR(lParam))

return;

else

{

switch(WSAGETSELECTEVENT(lParam))

{

case FD_READ:

...

break;

case FD_WRITE:

...

break;

...

}

}

█ 注意 ③:应用程序如何对 FD_WRITE 事件通知进行处理。

只有在三种条件下,才会发出 FD_WRITE 通知:

■ 使用 connect 或 WSAConnect,一个套接字首次建立了连接。

■ 使用 accept 或 WSAAccept,套接字被接受以后。

■ 若 send、WSASend、sendto 或WSASendTo 操作失败,返回了 WSAEWOULDBLOCK 错误,而且缓冲区的空间变得可用。

因此,作为一个应用程序,自收到首条 FD_WRITE 消息开始,便应认为自己必然能在一个套接字上发出数据,

直至一个send、WSASend、sendto 或WSASendTo 返回套接字错误 WSAEWOULDBLOCK。

经过了这样的失败以后,要再用另一条 FD_WRITE 通知应用程序再次发送数据。

代码:

[cpp] view plain copy
<span style="font-size:14px;">服务器端:
UINT CServerDlg::ThreadFun(LPVOID pParam )
{
CServerDlg* pDlg=(CServerDlg*)pParam;
pDlg->InitSock(); SOCKADDR_IN serAdd;
serAdd.sin_family=AF_INET; //AF_INET表示地址族,在windows下与PF_INET(协议族)是一样的
serAdd.sin_port=htons(5000);
serAdd.sin_addr.s_addr=ADDR_ANY;
pDlg->m_listenSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //创建套接字
if (INVALID_SOCKET==pDlg->m_listenSock)
{
AfxMessageBox(_T("初始化套接字失败"));
return 0;
}
if(SOCKET_ERROR==bind(pDlg->m_listenSock,(SOCKADDR*)&serAdd,sizeof(SOCKADDR)))
{
AfxMessageBox(_T("绑定地址失败"));
return 0;
}
if (SP_ERROR==listen(pDlg->m_listenSock,SOMAXCONN))
{
AfxMessageBox(_T("启动监听失败"));
return 0; }
//向windows注册
WSAAsyncSelect(pDlg->m_listenSock,pDlg->GetSafeHwnd(),WM_SOCKET,FD_ACCEPT | FD_CLOSE);
//当有感兴趣的事件发生时用Windows消息通知
//在窗口过程中实现该消息的判断
} LRESULT CServerDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和/或调用基类
//在网络事件中wParam代表了句柄 lParam的高位表示了错误信息 低位表示了相关的网络事件 switch(message)
{
case WM_SYSCOMMAND:
{
if(SC_CLOSE==wParam)
{
if(m_listenSock)
closesocket(m_listenSock);
if (m_cliSock)
closesocket(m_cliSock);
WSACleanup();
}
}
break;
case WM_SOCKET:
if (WSAGETASYNCERROR(lParam)) //WSAGENSELECTERROR宏获得是否有错误 这里用HIWORD(lParam)也是可以的
{
MessageBox(_T("网络出错"));
closesocket(wParam);
return 0;
}
switch(WSAGETSELECTEVENT(lParam)) //WSAGETSELECTEVENT获取网络事件 这里也可以用LODORD
{
case FD_ACCEPT: //case里定义变量时要加入{}
{
SOCKADDR_IN cliAdd;
int len=sizeof(SOCKADDR);
m_cliSock=accept(wParam,(SOCKADDR*)&cliAdd,&len);
WSAAsyncSelect(m_cliSock,this->GetSafeHwnd(),WM_SOCKET,FD_READ | FD_WRITE |FD_CLOSE); //该套接字也要用WSAAsyncSelect处理
if (m_cliSock==INVALID_SOCKET)
{
MessageBox(_T("接收连接出错"));
return 0;
}
}
break;
case FD_READ:
{
TCHAR bufData[1024]={0};
int flag;
flag=recv(m_cliSock,(char*)bufData,1024,0);
if(flag==0)
{
MessageBox(_T("连接已经断开"));
return 0;
}
ShowMsg(bufData);
}
break;
case FD_WRITE:
wParam=wParam; //不做处理
break;
case FD_CLOSE:
closesocket(wParam);
WSACleanup();
break;
default:
break;
} }
return CDialog::WindowProc(message, wParam, lParam);
}

  

本文转载于:http://blog.csdn.net/skyandcode/article/details/8646630

windows下的IO模型之异步选择(WSAAsyncSelect)模型的更多相关文章

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

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

  2. windows下的IO模型之事件选择(WSAEventSelect)模型

    异步选择模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知.对于异步选择模型采用的网络事件来说,它们均可原封不动地移植到事件选择模型.事件选择模型和异步选择模型最主要的 ...

  3. 三.Windows I/O模型之事件选择(WSAEventSelect )模型

    1.事件选择模型:和异步选择模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知.对于异步选择模型采用的网络事件来说,它们均可原封不动地移植到事件选择模型.事件选择模型和 ...

  4. windows下的IO模型之选择(select)模型

    1.选择(select)模型:选择模型:通过一个fd_set集合管理套接字,在满足套接字需求后,通知套接字.让套接字进行工作. 选择模型的核心是FD_SET集合和select函数.通过该函数,我们可以 ...

  5. 机器学习模型从windows下 spring上传到预发布会导致模型不可加载

    1.通过上传到redis,程序通过redis拉取模型,解决问题. 2.问题原因初步思考为windows下模型文件上传到 linux导致,待继续跟进查找.

  6. windows下的IO模型之完成端口

    本文整理于:http://blog.csdn.net/piggyxp/article/details/6922277 一. 完成端口的优点 完成端口会充分利用Windows内核来进行I/O的调度,是用 ...

  7. socket 异步选择 WSAAsyncSelect 用法

    WSAAsyncSelect 实现给异步socket给了另一种实现方式,就是通过窗口消息的方式来提醒对socket接收还是发送 msdn有非常全面的解释:https://msdn.microsoft. ...

  8. windows下C语言调用系统文件选择对话框

    代码片段,在windows下用C语言调用文件选择对话框,以备忘 #define DEFAULT_DIR "" char extraction_path[MAX_PATH] = DE ...

  9. windows下几种I/O端口(了解)

    如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的.Windows操作系统提供了选择(Select).异步选择(WSAAsyncSelect).事件选择(WSAEventSel ...

随机推荐

  1. Windows 7 Ultimate(旗舰版)SP1 32/64位官方原版下载地址

    MSDN于2011年5月12日,最新发布简体中文Windows 7 Ultimate 旗舰版 SP1 DVD镜像安装包,分32位和64位两个版本.最新发行代号分别是:677486(32位),67740 ...

  2. Haskell ghci中调用pandoc的API进行markdown转换

    所用环境:Windows Server 2008 + ghc 7.6.3(Haskell Platform 2013.2.0.0自带的) + pandoc 1.12.4 操作步骤: 1. 安装Hask ...

  3. Git 进阶之底层相关

    Git is a content-addressable filesystem. 1. Plumbing 和 Porcelain "Plumbing commands": Git ...

  4. 运行mlflow命令报错 The 'nose' distribution was not found and is required by nose-exclude

    安装好mlflow之后命令行运行: mlflow 得到报错: 解决: sudo pip3 install nose

  5. SELINUX导致数据修改权限不成功

    SELINUX导致数据修改权限不成功基本概念参考:https://blog.csdn.net/yanjun821126/article/details/80828908 查看SELinux状态: ./ ...

  6. SQL Server分区键列必须是主键一部分

    SQL Server分区键列必须是主键一部分. 必须把分区列包含在主键/唯一约束/唯一索引的键列中. USE tempdb GO -- 测试表 CREATE TABLE dbo.tb( id int, ...

  7. openSession()与getCurrentSession()的区别

    getCurrentSession创建的session会和绑定到当前线程,而openSession不会. getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSes ...

  8. 模块讲解----反射 (基于web路由的反射)

    一.反射的实际案例: def main(): menu = ''' 1.账户信息 2.还款 3.取款 4.转账 5.账单 ''' menu_dic = { ':account_info, ':repa ...

  9. L1正则与L2正则

    L1正则是权值的绝对值之和,重点在于可以稀疏化,使得部分权值等于零. L1正则的含义是 ∥w∥≤c,如下图就可以解释为什么会出现权值为零的情况. L1正则在梯度下降的时候不可以直接求导,可以有以下几种 ...

  10. 01 - spring mvc 概述及配置DispatcherServlet

    1.Spring mvc 基于model2实现,整体框架流程如(图片来自百度): ①web容器接收到http请求,若匹配DispatcherServlet的请求映射路径(web.xml),则容器会交给 ...