IOCP模型编程注意点

乱序问题

问题描述:客户端依次发送Msg1,Msg2,Msg3,服务器的逻辑处理的顺序不一定是Msg1,Msg2,Msg3

产生原因:

 三个线程同时从IOCP中读取Msg1, Msg2,与Msg3。由于TCP本身消息传递的有序性,所以,在IOCP队列内,Msg1-Msg2-Msg3保证了有序性(注意:数据在IOCP队列中数据顺序肯定是对的,乱序问题的产生在线程GetQueuedCompletionStatus之后到交给逻辑处理层的过程中)。三个线程分别从IOCP中取出Msg1,Msg2与Msg3,然后三个线程都会将各自取到的消息投递到逻辑层处理。在逻辑处理层的实现,我们不应该假定Msg1-Msg2-Msg3顺序,原因其实很简单,在GetQueuedCompletionStatus后到交给逻辑处理层的时间段内,三个线程被操作系统调度的先后次序是不确定的,所以在到达逻辑处理层,Msg1,Msg2与Msg3的次序也就是不确定的。所以,逻辑处理层的实现,必须考虑消息乱序的情况,必须考虑多线程环境下的程序实现。需要注意到是,这个乱序根本问题是由于多线程的调度产生的,与投递多少个WSARecv是没有关系到,就算你同时投递多个WSARecv,数据在IOCP队列中数据顺序肯定是对的。(我说的顺序对,指的是和数据到达网卡的顺序是一致的)

解决方法:

解决之前先解释一个问题,就是WSARecv和WSASend的有序性。例如:服务器端for循环3次依次投递多个WSARecv,投递时所对应的接收缓冲区分别是buf1,buf2,buf3,网卡上依次来了3次数据data1,data2,data3,(这3组数据是客户端的一个data数据按照顺序拆分出来的)那么能够保证的是这三组数据,存放的顺序一定是先放buf1,再放buf2,再放buf3.(会有这种情况:data1太大buf1不够了,data1的一部分在buf2中。但能够保证的是,分别将buf1,buf2,buf3中的接收到的数据取出再组合,肯定就是data数据),不会出现data2在buf1中,而data1却在buf2中,或者其他乱序的情况都不会出现。
有了上述前提,我们只需要在投递WSARecv时为每一个buf进行编号,然后创建一个接收缓冲区,per-sock-handle中记录当前要读的编号和要安排下次投递的编号,接收到数据时,根据buf编号和per-sock-handle中的编号来决定是要放入缓冲区(按照编号顺序存放)还是直接交给逻辑层。


粘包问题

问题描述:

这是tcp编程大多数情况不得不考虑的问题,(短链接和数据只管顺序收发(例如文件传输)的不用考虑)
不知道有多少前人掉在TCP Socket
send(人多)send(病少)send(财富)
recv(人多病)recv(少财富)
陷阱里面啊!
假设接收缓冲区4K,客户端先发送5K的数据(全是a),然后再次发送2K的数据(全是b),结果是服务器端先收到4K的数据(全是a),然后收到3K的数据(1K的a + 2K的b),这时我们要正确区分原来的完整数据是什么(5K的a 和 2K的b),重新组合后交给逻辑层处理

产生原因:

TCP流式传送数据

解决办法:

基本思路是按格式发送数据,一般为  固定消息头+数据总长度+数据内容   首先将待处理的接收数据流(长度设为m)强行转换成预定的结构数据形式,并从中取出结构数据长度字段,而后根据n计算得到第一包数据长度。
1)若n<m,则表明数据流包含多包数据,从其头部截取n个字节存入临时缓冲区,剩余部分数据依此继续循环处理,直至结束。
2)若n=m,则表明数据流内容恰好是一完整结构数据,直接将其存入临时缓冲区即可。
3)若n>m,则表明数据流内容尚不够构成一完整结构数据,需留待与下一包数据合并后再行处理。

你可能感兴趣的:(iocp,乱序,粘包)