IOCP中在WSASend以及WSARecv的时候出现WSA_IO_PENDING情况的说明

应该是windows网络编程第二版里面提到过。现在整理一下。

1:在IOCP中投递WSASend返回WSA_IO_PENDING的时候,表示异步投递已经成功,但是稍后发送才会完成。这其中涉及到了三个缓冲区。
网卡缓冲区,TCP/IP层缓冲区,程序缓冲区。
情况一:调用WSASend发送正确的时候(即立即返回,且没有错误),TCP/IP将数据从程序缓冲区中拷贝到TCP/IP层缓冲区中,然后不锁定该程序缓冲区,由上层程序自己处理。TCP/IP层缓冲区在网络合适的时候,将其数据拷贝到网卡缓冲区,进行真正的发送。
情况二:调用WSASend发送错误,但是错误码是WSA_IO_PENDING的时候,表示此时TCP/IP层缓冲区已满,暂时没有剩余的空间将程序缓冲区的数据拷贝出来,这时系统将锁定用户的程序缓冲区,按照书上说的WSASend指定的缓冲区将会被锁定到系统的非分页内存中。直到TCP/IP层缓冲区有空余的地方来接受拷贝我们的程序缓冲区数据才拷贝走,并将给IOCP一个完成消息。
情况三:调用WSASend发送错误,但是错误码不是WSA_IO_PENDING,此时应该是发送错误,应该释放该SOCKET对应的所有资源。

2:在IOCP中投递WSARecv的时候,情况相似。
情况一:调用WSARecv正确,TCP/IP将数据从TCP/IP层缓冲区拷贝到缓冲区,然后由我们的程序自行处理了。清除TCP/IP层缓冲区数据。
情况二:调用WSARecv错误,但是返回值是WSA_IO_PENDING,此时是因为TCP/IP层缓冲区中没有数据可取,系统将会锁定我们投递的WSARecv的buffer,直到TCP/IP层缓冲区中有新的数据到来。
情况三:调用WSARecv错误,错误值不是WSA_IO_PENDING,此时是接收出错,应该释放该SOCKET对应的所有资源。

在以上情况中有几个非常要注意的事情:
系统锁定非分页内存的时候,最小的锁定大小是4K(当然,这个取决于您系统的设置,也可以设置小一些,在注册表里面可以改,当然我想这些数值微软应该比我们更知道什么合适了),所以当我们投递了很多WSARecv或者WSASend的时候,不管我们投递的Buffer有多大(0除外),系统在出现IO_PENGDING的时候,都会锁定我们4K的内存。这也就是经常有开发者出现WSANOBUF的情况原因了。

我们在解决这个问题的时候,要针对WSASend和WSARecv做处理
1:投递WSARecv的时候,可以采用一个巧妙的设计,先投递0大小Buf的WSARecv,如果返回,表示有数据可以接收,我们开启真正的recv将数据从TCP/IP层缓冲区取出来,直到WSA_IO_PENGDING.
2:对投递的WSARecv以及WSASend进行计数统计,如果超过了我们预定义的值,就不进行WSASend或者WSARecv投递了。
3:现在我们应该就可以明白为什么WSASend会返回小于我们投递的buffer空间数据值了,是因为TCP/IP层缓冲区小于我们要发送的缓冲区,TCP/IP只会拷贝他剩余可被Copy的缓冲区大小的数据走,然后给我们的WSASend的已发送缓冲区设置为移走的大小,下一次投递的时候,如果TCP/IP层还未被发送,将返回WSA_IO_PENGDING。
4:在很多地方有提到,可以关闭TCP/IP层缓冲区,可以提高一些效率和性能,这个从上面的分析来看,有这个可能,要实际的网络情况去实际分析了。

时间: 2024-10-29 15:45:57

IOCP中在WSASend以及WSARecv的时候出现WSA_IO_PENDING情况的说明的相关文章

windows WSABUF 结构在IOCP 中应用时两个成员变量的意义

WSABUF 结构的原型如下: 1 typedef struct __WSABUF 2 { 3 u_long len; 4 char FAR *buf; 5 } WSABUF, *LPWSABUF; 该结构在IOCP 中用于函数WSARecv() 和WSASend() 函数的第二个参数,同时第三个参数指定该参数做为数组时的数组元素个数. 而该结构在两个函数中的意义也有小小的不同,主要在于 WSABUF::len 这个参数.它做WSARecv() 函数的参数时,len 被理解为缓冲区WSABUF:

阿里巴巴 2015 实习笔试题 分布式系统中的RPC请求经常出现乱序的情况 写一个算法来将一个乱序的序列保序输出

分布式系统中的RPC请求经常出现乱序的情况. 写一个算法来将一个乱序的序列保序输出.例如,假设起始序号是1,对于(1, 2, 5, 8, 10, 4, 3, 6, 9, 7)这个序列,输出是: 1 2 3, 4, 5 6 7, 8, 9, 10 上述例子中,3到来的时候会发现4,5已经在了.因此将已经满足顺序的整个序列(3, 4, 5)输出为一行. 要求: 1. 写一个高效的算法完成上述功能,实现要尽可能的健壮.易于维护 2. 为该算法设计并实现单元测试 貌似效率不是很高,有时间的时候改进下.

学习IOS开问题篇--类中的成员变量如果不实例化是什么情况

@interface Person : NSObject @property (noatonmic,copy) NSString * name; @end 一个person类,name是person得成员变量 如果在一个类中写入person为成员变量 self.person.name = @"zhangsan"; 如果前面不将person实例化,实际上是在对一个空指针进行操作 [nil setname:@"zhangsan"]; 因为oc中对空指针发消息不会报错,所

关于Android PopupWindow中实用Spinner控件点击APP Crash情况整理!

场景异常信息如下: android.view.WindowManager$BadTokenException: Unable to add window -- token [email protected] is not valid; is your activity running? at android.view.ViewRootImpl.setView(ViewRootImpl.java:646) at android.view.WindowManagerGlobal.addView(Wi

mybatis sql语句中 like in() 长度为0或null的情况

mybatis sql语句中 like in() 长度为0或null的情况 比如: select * from A where colName LIKE IN <foreach collection="moCodeList" item="item" index="index" open="(" close=")" separator=","> #{item} </for

iocp中GetQueuedCompletionStatus 121 信号灯超时时间已到 (error sem timeout)

报错 :121 信号灯超时时间已到 (error sem timeout) 现象和 http://bbs.csdn.net/topics/370175898 描述一致 现象:GetQueuedCompletionStatus 返回后,GetLastError = 121 (信号灯超时时间已到),出现这个提示后,服务程序变卡,客户端不能流畅的接收数据:没有这个错误则客户端接收流畅. 代码如下 void App::AnalysisCommand(const boost::system::error_

TCP中异常关闭链接的意义 异常关闭的情况

终止一个连接的正常方式是发送FIN. 在发送缓冲区中 所有排队数据都已发送之后才发送FIN,正常情况下没有任何数据丢失. 但我们有时也有可能发送一个RST报文段而不是F IN来中途关闭一个连接.这称为异常关闭 . 进程关闭socket的默认方式是正常关闭,如果需要异常关闭,利用 SO_LINGER选项来控制. 异常关闭一个连接对应用程序来说有两个优点: (1)丢弃任何待发的已经无意义的 数据,并立即发送RST报文段: (2)RST的接收方利用关闭方式来 区分另一端执行的是异常关闭还是正常关闭.

C++中虚函数的理解,以及简单继承情况下的虚函数的表!

面向对象的三大特征=封装性+继承性+多态性 封装=将客观事物抽象成类,每个类对自身的数据和方法实行权限的控制 继承=实现继承+可视继承+接口继承 多态=将父类对象设置成为和一个或者更多它的子对象相等的技术, 用子类对象给父类对象赋值之后, 父类对象就可以根据当前赋值给它的子对象的特性一不同的方式运作 C++的空类有哪些成员函数 1.缺省构造函数 2.缺省拷贝构造函数 3.缺省析构函数 4.缺省赋值运算符 5.缺省取址运算符 6.缺省取址运算符const PS:只有当实际使用的时候才会去使用这些类

DOM中关于脱离文档流的几种情况分析

所谓的文档流,指的是元素排版布局过程中,元素会自动从左往右,从上往下的流式排列.并最终窗体自上而下分成一行行, 并在每行中按从左至右的顺序排放元素.脱离文档流即是元素打乱了这个排列,或是从排版中拿走. 当前所知的脱离文档流的方式有两种:浮动和定位. a.定位属性positon 先看一下定位.看一段对定位各个字段的描述,有助于理解 值 描述 absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位. 元素的位置通过 "left", "top&q