null
通知套接口有请求事件发生.
#include <winsock.h>
int PASCAL FAR WSAAsyncSelect ( SOCKET s, HWND hWnd,
unsigned int wMsg, long lEvent );
s 标识一个需要事件通知的套接口的描述符.
hWnd 标识一个在网络事件发生时需要接收消息的窗口句柄.
wMsg 在网络事件发生时要接收的消息.
lEvent 位屏蔽码,用于指明应用程序感兴趣的网络事件集合.
本函数用来请求Windows Sockets DLL为窗口句柄发一条消息-无论它何时检测到由lEvent参数指明的网络事件.要发送的消息由wMsg参数标明.被通知的套接口由s标识.
null 本函数自动将套接口设置为非阻塞模式.
lEvent参数由下表中列出的值组成.
值 意义
FD_READ 欲接收读准备好的通知.
FD_WRITE 欲接收写准备好的通知.
FD_OOB 欲接收带边数据到达的通知.
FD_ACCEPT 欲接收将要连接的通知.
FD_CONNECT 欲接收已连接好的通知.
FD_CLOSE 欲接收套接口关闭的通知.
启动一个WSAAsyncSelect()将使为同一个套接口启动的所有先前的WSAAsyncSelect()作废. 例如,要接收读写通知,应用程序必须同时用FD_READ和FD_WRITE调用WSAAsyncSelect(),如下:
rc = WSAAsyncSelect(s, hWnd, wMsg, FD_READ|FD_WRITE);
对不同的事件区分不同的消息是不可能的.下面的代码将不会工作;第二个调用将会使第一次调用的作用失效,只有FD_WRITE会通过wMsg2消息通知到.
rc = WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);
rc = WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);
如果要取消所有的通知,也就是指出Windows Sockets的实现不再在套接口上发送任何和网络事件相关的消息,则lEvent应置为0.
rc = WSAAsyncSelect(s, hWnd, 0, 0);
尽管在本例中,WSAAsyncSelect()立即使传给该套接口的事件消息无效, 仍有可能有消息等在应用程序的消息队列中.应用程序因此也必须仍准备好接收网络消息-即使消息作废.用closesocket()关闭一个套接口也同样使WSAAsyncSelect()发送的消息作废,但在closesocke()之前队列中的消息仍然起作用.
由于一个已调用accept()的套接口和用来接收它的侦听套接口有同样的属性, 任何为侦听套接口设置的的WSAAsyncSelect()事件也同样对已接收的套接口起作用.例如, 如果一个侦听的套接口有WSAAsyncSelect()事件FD_ACCEPT,FD_READ,FD_WRITE, 则任何在那个侦听的套接口上接收的套接口将也有FD_ACCEPT,FD_READ,FD_WRITE事件,以及同样的wMsg的值.若需要不同的wMsg及事件,应用程序应调用WSAAsyncSelect(),将已接收的套接口和想要发送的新消息作为参数传递.
当某一套接口s上发生了一个已命名的网络事件,应用程序窗口hWnd会接收到消息wMsg.wParam参数标识了网络事件发生的套接口.lParam的低字指明了发生的网络事件.lParam的高字则含有一个错误代码.该错误代码可以是winsock.h中定义的任何错误.
错误代码和事件可以通过WSAGETSELECTERRORH和WSAGETSELECTEVENT宏从lParam中取出.定义如下:
#define WSAGETSELECTERROR(lParam) HIWORD(lParam)
#define WSAGETSELECTEVENT(lParam) LOWORD(lParam)
注意:在accept()调用和为改变事件或wMsg的WSAAsyncSelect()调用中有一个计时窗口.应用程序如果需要给侦听的和调用过accept()的套接口以不同的wMsg,它就应该在侦听的套接口上请求FD_ACCEPT事件,然后在accept()调用后设置相应的事件.由于FD_ACCEPT从不发送给已连接的套接口,而FD_READ,FD_WRITE,FD_OOB及FD_CLOSE也从不发送给侦听套接口,所以不会产生困难.
使用以上的宏将最大限度的提高应用程序的可移植性.
返回的可能网络事件如下:
值 意义
FD_READ 套接口s准备读
FD_WRITE 套接口s准备写
FD_OOB 带外数据准备好在套接口s上读.[1]
FD_ACCEPT 套接口s准备接收新的将要到来的连接.
FD_CONNECT 套接口s上的连接完成.
FD_CLOSE 由套接口s标识的连接已关闭.
返回值:
0 若应用程序感兴趣的网络事件的声明成功.
SOCKET_ERROR 否则.可通过调用WSAGetLastError()返回特定的错误代码.
评价:
尽管WSAAsyncSelect()可以以多个事件的组合来调用,应用程序窗口还是会为每个网络事件接收一条消息.
如同select()函数,WSAAsyncSelect()会被频繁地调用来决定,何时一次数据转移操作(send()或recv())可以启动,并且可以立刻成功.尽管如此,健壮的应用程序必须做好这样的准备, 即它可能接收到消息及启动了一个会立即返回WSAEWOULDBLOCK的Windows Sockets API调用.例如,下列的事件序列是可能的:
(i) 数据到达套接口s;Windows Sockets传递WSAAsyncSelect消息.
(ii) 应用程序处理其它一些消息.
(iii) 在处理过程中,应用程序启动了ioctlsocket(s,FIONREAD...)并且注意到有数据准备好读.
(iv) 应用程序启动recv(s,...)来读数据.
(v) 应用程序循环处理下一条消息,最终到达WSAAsyncSelect消息,表示数据已准备好读.
(vi) 应用程序启动recv(s,...),但失败并有错误WSAEWOULDBLOCK.
其它的事件序列也是可能的.
Windows Sockets DLL不会不断地为某一特定的网络事件向一个应用程序发送消息. 如果已成功地向应用程序窗口发送了一特定事件的通知,对该应用程序窗口将不再为该网络事件发消息,直到应用程序调用函数隐含地重新通知该网络事件.
重新通知函数
FD_READ recv()或recvfrom()
null FD_WRITE send()或sendto()
FD_OOB recv()
FD_ACCEPT accept()
FD_CONNECT 无
FD_CLOSE 无
任何对重新通知函数的调用,即使失败,也会达到为相关事件发重新通知消息的效果.
对FD_READ,FD_OOB和FD_ACCEPT事件,消息传递是"水平触发"(level-triggered)的.这意味着,若调用了重新通知函数并且相关的事件对该调用仍有效,WSAAsyncSelect()消息就将传给应用程序.这为应用程序提供了事件驱动以及不必考虑在任一时刻到达的数据量的能力.考虑下列序列:
(i) Windows Sockets DLL在套接口s上接收100字节的数据并传递一个FD_READ消息.
(ii) 应用程序启动recv(s,buffptr,50,0)接收50字节.
(iii) 由于仍有数据未读,Windows Sockets DLL发送另一个FD_READ消息.
根据以上语义,应用程序不必在收到FD_READ消息时读进所有可读的数据-对应于每一FD_READ消息进行一次recv()调用是恰当的.如果应用程序为一个FD_READ消息而启动了多个recv()调用,它将接收到多个FD_READ消息.这样的应用程序可能希望在开始recv()调用( 通过不为FD_READ事件置位的WSAAsyncSelect()函数调用)之前关闭FD_READ消息.
如果在应用程序初次调用WSAAsyncSelect()或当调用了重新通知函数时,有一个事件为真, 则会发送一个相应的消息.例如,若应用程序调用listen(),就会试图进行连接,然后应用程序调用WSAAsyncSelect()声明它需要为套接口接收FD_ACCEPT消息,Windows Sockets的实现就会立即传递一个FD_ACCEPT消息.
FD_WRITE事件处理起来稍有不同.FD_WRITE消息是在套接口第一次用connect()连接或由accept()接受,并且在send()或sendto()以WSAWOULDBLOCK错误失败后缓冲区空闲时发送的.因此,应用程序可以假设发送可能在第一次FD_WRITE消息时开始,并持续到一次返回WSAEWOULDBLOCK的发送. 在这样的失败后,应用程序将被通知,FD_WRITE消息的发送又将可能.
FD_OOB事件只用在当套接口配置成独立接收带外数据时.如果一个套接口被配置成接收感兴趣的带外数据状态,带外数据将和普通数据等同视之,并且应用程序应该注册它感兴趣的方面,然后将接收FD_READ事件,而不是FD_OOB事件.应用程序可以设置或监控带外数据处理的方法(通过使用setsockopt()或getsockopt()函数,及SO_OOBINLINE选项).
在FD_CLOSE消息中的错误代码指出套接口的关闭是正常的还是异常的.如果错误代码是0,则关闭是正常的;若错误代码是WSAECONNRESET,则套接口的虚套接口将被重置.这些只对SOCK_STREAM类型的套接口起作用.
FD_CLOSE消息在相应套接口的虚电路关闭指令接收到时发送.在TCP术语中,这意味着FD_CLOSE在连接进入了FIN WAIT或CLOSE WAIT状态时发送.这是远端对发送方进行了shutdown()调用或closesocket()调用的结果.
请注意你的应用程序将只会收到FD_CLOSE消息来指出虚电路的关闭.它不会收到FD_READ消息来表示该状况.
WSANOTINITIALISED 在使用本API前必须进行一次成功的WSAStartup()调用.
WSAENETDOWN WINDOWS SOCKETS实现已检测到网络子系统故障.
WSAEINVAL 指出指定的参数之一是非法的.
WSAEINPROGRESS 一个阻塞的Windows Sockets操作正在进行.
附加的错误代码可能在应用程序窗口接收到消息时被置.这些代码可以用WSAGETSELECTERROR宏从lParam中取出.对应于每个网络事件的可能错误代码为:
事件:FD_CONNECT
WSAEADDRINUSE 给定的地址已被使用.
WSAEADDRNOTAVAIL 指定的地址在本地机器不能使用.
null WSAEAFNOSUPPORT 指定族的地址不能和本套接口同时使用.
WSAECONNREFUSED 连接的尝试被拒绝.
WSAEDESTADDRREQ 需要一个目的地址.
WSAEFAULT namelen参数不正确.
WSAEINVAL 套接口已经约束到一个地址.
WSAEISCONN 套接口已经连接.
WSAEMFILE 没有可用的文件描述符.
WSAENETUNREACH 此时网络不能从该主机访问.
WSAENOBUFS 无可用的缓冲区空间.套接口不能连接.
WSAENOTCONN 套接口没有连接.
WSAENOTSOCK 该描述符是文件,不是套接口.
WSAETIMEDOUT 试图连接超时,未建立连接.
事件:FD_CLOSE
WSAENETDOWN WINDOWS SOCKETS实现已检测到网络子系统故障.
WSAECONNRESET 连接由远端重建.
WSAECONNABORTED 由于超时或其它失败放弃连接.
事件:FD_READ
事件:FD_WRITE
事件:FD_OOB
事件:FD_ACCEPT
WSAENETDOWN WINDOWS SOCKETS实现已检测到网络子系统故障.
关于Windows Sockets提供者的说明:
Windows Sockets的提供者应确保消息可以成功地传给应用程序.如果PostMessag()操作失败,Windows Sockets的实现必须重发该消息-只要窗口存在.
Windows Sockets提供者应使用WSAMAKESELECTREPLY宏来构造消息中的lParam参数.
当套接口关闭时,Windows Sockets提供者应清除所有保留下来要发送给应用程序窗口的消息.然而应用程序必须准备好接收,放弃任何在closesocket()之前可能已经发送的消息.
参见:
select()