在面向连接的流方式通信中,listen、recv、send都要等到出错或者相应请求完成时,函数才能返回。可是如果相应的请求在短时间内不能完成,则函数就不能返回,我们把这种现象叫做阻塞。在阻塞期间不能进行其他操作(类似于死机)为了解决这一问题,Winsock提供了一种异步模式,在这种模式下,函数调用后立即返回,Winsock通过函数WSAAsyncSelect()来实现非阻塞通信。
方法是:
由该函数指定某种网络事件,当被指定的网络事件发生时,由Winsock发送由程序约定好的消息。程序再对消息作出相应的消息处理..........
函数原型
int WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long 1Event);
Socket在这个函数调用中被自动设成非阻塞方式,hWnd是接收Winsock消息的窗口句柄,wMsg是向窗口发送的消息名称,用户自定义。1Event是被指定的网络事件
网络事件lEvent
FD_READ 希望Socket收到数据时发送读的消息
FD_WRITE 希望Socket发送数据时发送写的消息
FD_OOB 希望OOB data到达时发送到达的消息
FD_ACCEPT 希望有连接到来时发送连接请求的消息
FD_CONNECT 希望完成连接时发送连接完成的消息
FD_CLOSE 希望接收Socket关闭的消息
FD_QOS 希望接收Socket服务质量(QoS)变化的消息
FD_GROUP_QOS 希望接收Socket服务质量(QoS)不变的消息
FD_ROUTING_INTERFACE_CHANGE 希望接收指定的地址路由接口变化的消息
FD_ADDRESS_LIST_CHANGE 希望接收Socket协议族局部地址变化的消息
要注意的是,WSAAsyncSelect()的设定是针对某一个Socket的,如果开启了很多Socket,就需要让每个都呼叫函数来逐一设定。
【待续】
对于同一个套接口,多次启用WSAAsyncSelect()时,将使以前的WSAAsyncSelect()作废,如果要取消对某个套接口的所有消息通知则可:
WSAAsyncSelect(s,hWnd,0,0);
类似调用colsesocket(s)也同样可以吧网络消息作废.
注意一点:由于检测到连接请求而调用accept函数产生的套接口由于和监听套接口有相同的属性,所以新产生的接口也同样启用了非阻塞模式,在产生的对话套接口也用lParam来标示发生的网络事件。
【事件分析】
FD_READ;(要读取)如果要接收的是100个字节,而调用一次recv(sock,buff,50,0);一次接收了50个字节,当然还有50个没有接收,这时会再次发送一个FD_READ消息来读取,直到100个字节全部读取完毕为止。
FD_WRITE:【有点麻烦】当建立连接connect时会产生一个WRITE事件。 但是值得注意的一点是,并不是在收到WRITE事件后就直接send了,而是只有发送缓冲区有多出的空位, 可以容纳需要发送的数据时才会触发.意思是说,先要把缓冲区填满了。通常的办法是在一个无限循环中不断的发送数据, 直到把发送缓冲区填满. 当发送缓冲区被填满后, send() 将会返回 SOCKET_ERROR , WSAGetLastError() 会返回 WSAWOULDBLOCK . 如果当前这个 SOCKET 处于阻塞(同步)模式, 程序会一直等待直到发送缓冲区空出位置然后发送数据; 如果SOCKET是非阻塞(异步)的,那么你就会得到 WSAWOULDBLOCK 错误. 于是只要我们首先循环调用 send() 直到发送缓冲区被填满, 然
后当缓冲区空出位置来的时候, 系统就会发出FD_WRITE事件.
所以说如果不是一次性发送大批量的数据的话, 最好是不用 FD_WRITE 事件了, 因为如果你要发送的数据不能把缓冲区填满,那么你就只能收到连接刚刚建立时触发的那一次 FD_WRITE - 系统不会触发更多的 FD_WRITE消息了. 所以当你只是发送尽可能少的数据的时候, 不要用WRITE而是直
接send就行了.....
FD_OOB:想要恢复带外的数据到达的通知。带外数据(也称为TCP紧急数据、快速数据等)
只用在当套接口配置成独立接收带外数据时.如果一个套接口被配置成接收感兴趣的带外数据状态,带外数据将和普通数据等同视之,并且应用程序应该注册它感兴趣的方面,然后将接收FD_READ事件,而不是FD_OOB事件.应用程序可以设置或监控带外数据处理的方法(通过使用setsockopt()或getsockopt()函数,及SO_OOBINLINE选项).
FD_ACCEPT:我们在建立初始化服务器阶段,调用listen()开启监听套接口,当遇到wMsg传来FD_ACCEPT时来建立一个新socket,新的socket同样启动了非阻塞模式。这些所有已经创建的套接口,发现有网络事件时都会产生一条消息wMsg。