IOCP网络模型

. Socket I/O数据流向图
IOCP网络模型_第1张图片
SEND:
  阻塞模式:必须等待程序缓冲区中的数据全部拷贝到TCP/IP缓冲区后才返回
  非阻塞模式:查看TCP/IP缓冲区是否有剩余空间,有,则执行拷贝大小不超过剩余空间大小的程序缓冲区数据,成功后返回。无,则返回WSAEWOULDDBLOCK,提醒程序稍后再做尝试
RECV:
  阻塞模式:必须等待TCP/IP缓冲区数据到达,并拷贝至程序缓冲区后才返回
  非阻塞模式:查看TCP/IP缓冲区是否有数据到达,有,则执行拷贝操作成功返回。不满足,则返回WSAEWOULDDBLOCK,提醒程序稍后再做尝试

疑问1:网卡缓冲区,应该跟操作系统Socket接口无关吧?操作系统等到数据拷贝到TCP/IP缓冲区就视为I/O成功了,至于以后的事情,都交给TCP/IP协议来保证?

2. 完成端口模型中WSASend数据发送流程
IOCP网络模型_第2张图片

疑问2:如果使用完成端口,要注意调用WSASend的次序就是就是缓冲区被填充的次序。不要从不同的线程中同时调用同一个socket上的WSASend函数,因为可能导致缓冲区中的数据处于不可预知的次序! 
这句话如何理解呢? 根据我的理解WSASend是异步的I/O模式,调用WSASend时,除非TCP/IP缓冲区中有剩余空间,能够立即完成I/O操作,否则都要先将请求投递到操作系统I/O队列上,等待TCP/IP缓冲区空闲了才会执行I/O操作。
那么即使是不同线程同时调用WSASend,系统检测到之前已经有请求占用了TCP/IP缓冲区,必然会有序的将请求放入请求队列,如何又会造成不可预知的次序呢?莫非操作系统本身对于执行I/O请求操作也采用了线程池的机制吗?


3. 完成端口模型中WSARecv数据接收流程


疑问3:WSANOBUF错误产生原因:
当我们投递了很多WSARecv或者WSASend的时候,不管我们投递的Buffer有多大(0除外),系统在出现IO_PENGDING的时候,都会锁定非分页内存,系统锁定的时候,最小的锁定大小是4K(当然,这个取决于您系统的设置,也可以设置小一些,在注册表里面可以改,当然这些数值微软应该比我们更知道什么合适了) 
解决办法:
1:投递WSARecv的时候,可以采用一个巧妙的设计,先投递0大小Buf的WSARecv,如果返回,表示有数据可以接收,我们开启真正的recv将数据从TCP/IP层缓冲区取出来,直到WSA_IO_PENGDING.
2:对投递的WSARecv以及WSASend进行计数统计,如果超过了我们预定义的值,就不进行WSASend或者WSARecv投递了。

在我的理解必须先投递WSARecv请求,才可以通过完成端口收到数据到达的通知,根据条款2,如果服务器本身连接了数万的Client,那么同一时刻至少要保证必须投递个数与之对应的0大小Buf的WSARecv才能确保每个Client的数据接收能正常被监测到。那如果连接数本身就超过了我们预定义的最大值,那么后来再连上来的Client,服务器不是永远都不会响应其请求了吗?我这样理解对吗?
另还有一种说法说WSASend也要先投递0字节的buf,等完成通知到达了表示TCP/IP缓冲区空间剩余可进行I/O处理,然后再调用同步的send函数进行真正的数据发送。
这样子处理的话,那我必须要对每个ClientSocket维护一个发送队列,当0字节I/O请求完成通知未到达前,对于其他线程投递的Send请求都先放入这样队列中,统一等通知到达后发送。这样子的设计是不是会有点画蛇添足的感觉的,一方面I/O又变成了同步的,另一方面程序还要自身维护一个发送队列,反而增加了系统的开销


4. 完成端口模型中AcceptEx接受连接流程

来源:http://topic.csdn.net/u/20111028/23/f79f1b3e-a3a5-434e-b8ab-7973bbbe8f5c.html

你可能感兴趣的:(IOCP网络模型)