TCP协议提供面向连接的可靠数据传输,要想知道TCP是如何实现的,先要了解实现可靠传输需要哪些条件。
我们需要可靠数据传输协议这样的需求,是建立在通信的信道并不可靠的情况下的,下面就渐进式地引入不可靠因素,来逐步提出解决方案。
在描述传输过程的时候,通常使用有限状态机和状态转移图。
1、完全可靠的信道
在一个完全可靠的信道上,认为传输的信息不会出错,且一定会按顺序到达,此时就根本不需要可靠性协议,状态机如图:
Rdt 1.0:
发送方只管发,接收方只管收就行了。
2、会出现bit错误的信道
这种信道,在信息传输的中间过程可能会出现bit的翻转。
Rdt 2.0:
解决方法如下:
- 首先是检测错误,引入校验机制,检查当前的数据是否有误。
- 其次是引入错误恢复机制,即遇到错误之后怎么恢复数据的正常传输
- 引入反馈确认机制:接收方接收到消息后,如果校验正确,发ACK确认包;若校验失败,发NAK反馈包
- 引入重传机制:当发送方接收到NAK后,自动重传当前的包。
这就是所谓的 “停——等” 协议,状态机如下:
发送方在发完一个包之后,要等待接收方返回ACK/NAK来决定继续发送还是进行重传。
但 Rdt 2.0 也有自己的问题,如果回传的 ACK/NAK 包发生了错误咋办?
Rdt 2.1:
提出解决方案:
- 首先同样是检测错误,在发送方引入校验机制,校验收到的ACK/NAK包。
- 二是错误恢复
- 当收到损坏的ACK/NAK,直接重传,这就叫做简单重传机制。
但是引入简单重传机制的时候,如果是 ACK 包出现错误,并重传的时候。接收端就会收到重复的包,这又要引入两个机制:
- 包序列号:发送方对每个包标记序列号,在这种情况下,由于只对当前包和上一个包做判断,所以两个序列号就够用了。
- 分组丢弃:接收方收到相同序列号的包之后,把重复的包丢弃
此时状态机如下:
Rdt 2.1 已经解决了传输中的问题,在其基础上,我们可以进一步修改,主要针对这样一个问题:
是否需要NAK包?毕竟少一种类型就少一种判断。
Rdt 2.2:
这种时候可以利用序列号,当发送ACK包的时候,带上最后一次正确接收的序列号。发送方通过比较序列号就能判断收到包是哪一个了!
改进后的状态机如图:
3、会出现bit错误和数据丢失的信道
前面的信道,不管包是否错误,包总是能够到达的。但实际上包可能出现丢失,这就是我们实际使用的网络环境,很糟糕吧?
前面的协议本质上都是 “停——等” 协议,即发送方需要等待接收方的响应。但在数据会丢失的信道上就不能这么做了。如果确认包丢失了,那么发送方就会一直等下去。这就需要新的解决方案:
Rdt 3.0:
- 引入超时机制,即发送方等待一定的时间,如果超过这个时间,则认为包丢失了,进行重传。
实际上也是 “停——等” ,但因为数据包可能丢失,所以不一直等了。
执行过程如下:
到此,我们已经实现了一个可靠的传输协议,但其性能真的奇差无比,我们动手算一下。
示例:1Gbps链路,15ms端到端传播延迟,1KB分组
L = 1K * 8bit,R = 1G bit / s = 1Mbit / ms ==> t = 0.008 ms
RTT = 2 * 15ms = 30 ms;
在1Gbps链路上,完成一个包的发送需要30.008ms!实际速率仅 1k * 8bit / 30.008 ms = 0.267 Mbps
发送方利用率:发包时间0.008ms / 实际完成所需要时间30.008ms = 0.00027 即 0.027%。
这个协议对于信道的利用率实在太低了,下一章将会解析我们实际使用的TCP协议,看看它是如何在以上讨论的基础上提高效率的。
叨叨几句... NOTHING