【关于面向连接的异步模式】

简介: 【关于面向连接的异步模式】

在面向连接的流方式通信中,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。


相关文章
|
前端开发 JavaScript UED
|
前端开发
异步转同步的几种方法
在循环等待中,我们可以使用一个变量来指示异步操作是否已完成。然后,我们可以在循环中检查该变量,如果它指示异步操作已完成,则退出循环。
552 0
|
6月前
|
负载均衡 算法 前端开发
同步和异步
同步和异步
86 0
|
6月前
|
Python
同步和异步的区别
同步和异步的区别
|
JavaScript 前端开发 UED
同步和异步区别
同步和异步区别
151 0
|
6月前
同步和异步的区别?
同步和异步的区别?
159 0
|
6月前
|
存储 JavaScript 前端开发
|
6月前
|
前端开发 JavaScript
同步和异步有什么区别
同步和异步有什么区别
216 0
|
存储 SQL 设计模式
C#异步有多少种实现方式?
C#异步有多少种实现方式?
|
消息中间件 前端开发 数据库
同步与异步详细区别
还在等什么,快来一起讨论关注吧,公众号【八点半技术站】,欢迎加入社群