1 TCP可靠传输的实现
1.1 以字节为单位的滑动窗口
现在有主机A和主机B,假设主机A现在要将数据DATA(20个字节)经过网络传给主机B。在发送的时候,主机A有一个发送缓存,主机B有一个接收缓存。然后开始通信:
1)首先主机A和主机B先建立连接,建立连接的时候主机B要告诉主机A自己的接收窗口的大小,单位是字节(这里假设B的接收窗口大小为10字节),这个时候主机A就会设定自己的发送窗口的大小(A的发送窗口大小为10字节,不能超过B的接收窗口大小)。
2)连接建立完成后,主机A和主机B要相互通信了!
第一个数据包发了3个字节,不等待确认,继续发送第2个数据包,再继续发送第3个数据包。然后就不能继续发了,因为剩下的数据这会儿还在窗口外面呢。然后这些数据包在网上开始传。
此时,要注意的是,主机A在网络上传送的10个字节的数据在没有收到主机B的确认之前还不能在主机A上删除。
一段时间后,主机B收到了主机A发来的数据包,数了一下,发现这里的字节是连续的,OK!现在,主机B可以给主机A发一个确认数据包。确认序号为7,表示该发第7个字节的数据了。同时,主机B的接收窗口右移。主机A收到确认之后,就知道前面的数据包主机B已经正确无误的收到了,OK!主机A的发送窗口开始右移,而主机A前面的字节就删除掉了,因为主机B已经收到了。
与此同时,在主机A滑动窗口内的数据也可以在网上传了。接着,数据又开始陆续到达主机B了。。。(注意:缓存可以循环使用)
总结一下:
接受方(即主机B)在收到数据并回复确认之后,窗口开始移动;
发送方(即主机A)在收到接收方的确认回复后,窗口开始移动,并且删除掉已经确认收到的数据。
3)根据以上所讨论的,我们还要注意3点:
- 虽然A的发送窗口是根据B的接收窗口设置的,但在同一时刻,A的发送窗口并不总是和B的接收窗口一样大。这是因为通过网络传送窗口值要经历一定的时间滞后。另外,A还可能根据网络当时的拥塞情况适当减小自己的发送窗口数值。
- 对于不按序到达的数据应如何处理?TCP通常对不按序到达的数据是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付给上层的应用进程。
- TCP要求接收方必须有累积确认的功能,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息捎带上。但要注意两点:第一,接收方不应过迟发送确认,否则会导致发送方不必要的重传,反而浪费了网络的资源。第二,捎带确认实际上并不经常发生,因为大多数应用程序不同时在两个方向上发送数据。
1.2 超时重传时间的选择
TCP的发送方在规定的时间内没有收到确认就要重传已发送的报文段,这就是重传机制。但重传时间的选择就比较烧脑。如果把超时重传的时间设置得太短,就会引起很多报文段的不必要的重传,使网络负荷增大。但如果太长,会使网络的空闲时间增大,降低了传输效率。
那么传输层的超时重传时间究竟是怎样设置的呢?
TCP为了保证无论在任何环境下都能比较高性能的通信,会动态的计算超时重传时间。
- Linux(BSD Unix和Windows也是如此)中,超时以500ms为一个单位进行控制,每次判定超时重传的超时时间都是500ms的整数倍。
- 如果重发一次之后,仍然得不到应答,等待2*500ms后再进行重传。
- 如果仍然得不到应答,等待4*500ms进行重传。以此类推,以指数形式递增。
- 累积到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。