- 论坛徽章:
- 8
|
本帖最后由 shan_ghost 于 2013-12-10 11:46 编辑
叶叶叶Yeah 发表于 2013-12-10 00:22 ![]()
如果需要按顺序接收,那么在收到一个数据分节(segment)时为什么只检测分节里的序列号是否在接收窗口,而没有检测是否按顺序?
是不是RFC文档没有规定这些?
是不是TCP 收到一个数据分节后把它暂存起来? 这个时候TCP不会发送ACK 吗?
1、TCP保证上层应用看到的数据是有序的、可靠的;但TCP协议本身不要求来自网络的数据按顺序到来,且不出错、不丢包。
2、RFC有详细规定……不过偶只仔细看过快速重传、TCP windows相关方面的内容
3、不仅TCP在收到一个数据包后要把它暂存起来;发送端也要把发过的数据包暂存起来,只有收到ACK包才可以把数据从缓存中删除。
这其实就是TCP保证数据可靠性的具体机制: 发送方发一个包,但不能确定这个包可以被对端正确接收;所以它必须暂时缓存这个包,直到对端用ACK报告了“包XXX正确收到”这个信息。
如果超过一定时间收不到ACK,它就必须利用缓存里的备份重新发送该包。
而在接收端,如果收一个包就必须发一个ACK、且必须等接收端收到后才能继续;那么,对一个100ms延迟的网络,就意味着这套机制限制每200ms才能传输一个数据包。这显然是绝对无法接受的。
为解决这个问题,接收端就使用了一个叫做“滑动窗口”的特殊缓冲区。这就允许发送方可以连续发送总大小不大于这个缓冲区的数据;接收端则应尽快向发送方报告哪些包已经收到。
——事实上,发送端的发送缓冲区也是一个“滑动窗口”。
实际上,TCP接受到的数据,最终是要传送给上层应用程序的。所以,只有按顺序到达的那些数据才可以“搬”到应用程序的接收缓冲区(这个说法不够精确,但能尽量清晰的表达逻辑关系),从而为“滑动窗口”腾出更多空间(或者叫 允许滑动窗口左边界向右移动)——对于发送端,情况是一样的;不同的是,它是以收到ACK而不是“数据已移入应用读缓冲区”,作为移动滑动窗口的条件。
而不按顺序到达的数据呢,如果N+1、N+2先于N到了,那就先缓存N+1和N+2,等N到了、填补了空洞,再通过ACK报告“N+2及之前的所有包都已收到”。
因此,ACK报告的状态必须关联于“和前面数据连续的、最后一个包的尾部”,这才能保证滑窗正确动作。
最后,未按顺序到达的包,也可以使用SACK报告已经正确收到(SACK=selective ack,即选择性ACK:这个是后来的扩展,初期的TCP协议并没有定义这个)。
这可以避免出现“包N丢包,结果从N到N+M的所有包都被重发”问题。
另一种机制则是,当N尚未到、而N+1、N+2、N+3已经到达时,可以在N+1、N+2、N+3到达时反复报告N-1收到,这就是dup ack(重复的ACK)。
发送端发现dup ack,就说明接收端出现了乱序。当dup ack连续出现k次时,就说明包N可能已经丢了。此时它就可以不等重传计时器超时,立即重传包N。
这个机制可以避免滑动窗口长时间无法“滑动”(除非发送端重传计时器超时),进而避免进入拥塞控制逻辑(此时TCP协议认为网络带宽不足,会导致数据传输速率减半,需要较长时间才能恢复);但不合适的k值可能导致重传一些没有丢失的包(比如,当k为3,而包N乱序深度达到了6)。
早期,K值固定为3;现在则可通过一些机制来动态调整k值(或者改用时间控制)。 |
|