我的学习总结:
TCP连接方式是可以保证数据的顺序无重复到达.但不保存数据边界。
UDP不保证以上特点.但保存数据边界(数据边界我想就是可以用来区分是那一次发送)。
基于TCP方式的特点,可以认为TCP是一个流式的管道,数据是在里面连续流动的,这也是为什么无法保留数
据边界的原因,所以我们在编TCP程序的时候就有必要创建我们的数据边界,因为绝大多数程序是按一定的数据
包来处理的。因此在发送数据的过程中我们要定义一个数据包的包头(注意包头应该是定长的),比如最简单的
就是在每个发送的数据包前面加上将要发送的数据的尺寸及校验码,在接收端接收的时候先分析每个获取的数
据包的包头信息,如果包括校验码就说明这是一个包头,接着处理尺寸接收数据。
可能需要一次或多次接收才能接收一个完整的包(取决于你的当前网络环境,因为TCP有个接收窗口尺寸的问
题(它是根据网络状态自动调整的)所以可能出现一次发,多次收的情况,即使你的数据包非常小。),也可能一次
接收的数据包含两个包的信息,需要按照刚才说过的方法检测接收的数据。
对于完成端口也一样有同样的问题,因为它也是TCP方式的,解决的方法就是在接到完成信息时候使用如上的
方法对每个数据包都检测是否完整,如果不完整则暂存数据,等下一个完成信息收到后处理,此时可能有三种
情况发生,
一、新接收的数据正好是满足前一个数据包(本次接收的数据+上次接收的数据 = 包头定义的尺寸)。
二、新接收的数据还不满足前一个数据包(本次接收的数据+上次接收的数据 < 包头定义的尺寸)。
三、新接收的数据不仅满足前一数据包,还有剩余,此时还有两中可能。
(1)剩余部分>=包头尺寸。
(2)剩余部分<包头尺寸。
四、接收的数据包含部分包头数据。
那么针对以上的可能我们应该怎样处理呢?下面逐一解决:
第一种可能:
这是我们最期待的结果,可经验告诉我,这也是最少发生的可能,处理比较容易,我们只需要将数据
复制到缓冲中,然后唤醒处理线程或直接处理,缓冲复制完毕不要忘了再次投入一个WSARECV。
第二种可能:
复制数据到缓冲并再次投入一个WSARECV。
第三种可能:
(1)复制上一个包的数据到缓冲,执行处理,清空缓冲并复制包头数据,分析包头,记录下一数据包
尺寸,将剩余数据复制到缓冲中并再次投入一个WSARECV。
(2)复制上一个包的数据到缓冲,执行处理,复制剩余数据到包头缓冲,并指名包头剩余数据的尺寸
,并再次投入一个WSARECV。
第三种可能:根据包头剩余尺寸信息填充包头缓冲,分析包头,确定剩余数据是否满足本数据包,如 >= 则按
第三种可能处理,否则按第二种可能处理。
注意:以上所提到的缓冲为我们共用缓冲,可以由多个工作线程处理,因此在缓冲的读写时要注意同步。因为
在创建完成端口的时候我们可以指定没一个CPU上的并发线程数量,同时如果系统中存在多于一个以上的CPU时
都可能出现同一个缓冲被多个工作线程使用的可能,所以必须同步。另外为什么要在包头中加校验码,是因为
如果发送方突然断电或网络不通,当重新连接后在次发送可能会导致某一个处理会将其认为是上一数据包的延
续,但通过加校验码,接收方就可以在接收到信息的数据包是检查是否为包头,就可以将上一个包丢弃,从而
避免这类错误。当然也可以通过控制信息来实现此功能,但个人认为比较麻烦,同时未来的网络速度应该不是
问题,所以使用此方法:)。
下面是针对这个例子的OVERLAPPED的扩展定义。
THeaderInfo=record
ID:Array[0..9] of char;
Size:Integer;
end;
TOVERLAPPEDEX=record
oi
verlapped;
Header:THeaderInfo;//数据包头。
HeaderBuff
Char;//数据包头的指针(HeaderBuff:=@Header);
HeaderLoseSize:Integer;//包头剩余的尺寸。
WorkBuff
Char;//数据缓冲,应该来源于外部缓冲池。
end;
以上的定义只是用来学习,在实际应用中未过多测试。