TCP
协议栈支持全双工数据传递,可以同时发送和接收。那么他是如何保证可靠性?如何解决丢包、乱序等问题的呢?
An Unreliable Protocol
我们先来看不可靠协议的传输机制,比如说网络层IP协议,它是不可靠的,尽管有ICMP
(控制消息协议),但是没有ACK
,任然是不可靠的。
如上图所示,每一条消息发出去之后,并不知道对方有没有收到。
Positive Acknowledgment with Retransmission
为了保证消息准确到达,出现了 PAR机制,也就是带重传的肯定确认机制。
如上图所示,每一条消息发出去之后,我们启动一个计时器,等待对方告诉我们是否收到这条消息了。如果超时了,则进行重传。优缺点也很明显:
这样保证了传输可靠和顺序,适合数据交换频率低的场景。
缺点也很明显,效率不是很高,单位时间内的网络吞吐量比较低。
Enhanced Positive Acknowledgment with Retransmission
增强版的PAR 机制解决了普通PAR机制的效率问题,同时保证了传输的可靠性。主要有以下优化点:
- 增加了消息索引,一次可以发多条消息,每条消息单独确认;
- 保留了消息的计时器;
- 增加窗口机制,接收的负载,控制发送方的频率;
如上图所示,发送方可以发送多条消息,每一条消息启动一个计时器,等待消息的ACK。如果超时了,则进行重传;每一条消息会有一个窗口Limit
参数,如果超过这个大小,发送方就不能继续发送。需要等待已发消息的ACK,也就是等待接收方处理完消息。
Sliding Window System
和增强版的 PAR 类似,TCP
引入了 Sliding Window System 滑动窗口系统,实际上比前者要复杂很多。主要有以下更新:
增加了
Window
参数,表示剩余可接受的窗口大小。增加了
Seq
(已发送的字节数)和Ack
(已接收的字节数)。
发送窗口
因为TCP协议支持全双工的,那么有发送和接收这两个块缓冲区。我们先看发送的缓冲区:
我们来介绍下关键的几个名词:
1. Send Window
发送窗口,包含已发送待确认的窗口、未发送接收方准备好接收的窗口。
2. Already Sent Window
已发送的窗口,即已发送待确认的窗口。
3. Usable Window
可用窗口,即未发送接收方准备好接受的窗口。
4. Left Edge of Send Window
发送窗口的左边界,也就是已发送最后收到确认字节。
5. Right Edge of Send Window
发送窗口的右边界,也就是可以发送的最大字节。
接收窗口
接收的缓冲区比较简单,和发送窗口不一样,接收窗口没有待确认的部分:
1. Receiver Window
接收窗口。
2. Advertised Window
空闲的窗口,等于接收窗口 - 最后收到的字节。
窗口滑动
如上图这种情况,发送端发送了 3、4、5三个Segment
,接收端收到了3、5,4丢失了,接收端会回复收到的连续字节最后的位置,也就是回一个ACK
3的消息,发送端收到ACK
3的消息后,窗口左边缘滑到4的位置,如下图所示:
如果超时还没有收到4的ACK
,则进行重传。
SEQ ACK
仅仅依靠滑动窗口并不能解决丢包乱序的问题,还有两个很重要的元素就是序号和确认号。
1. Seq(Sequence number)
序号,跟踪已发送的数据,解决乱序问题。
- SYN控制位=1,值为初始序列号 ISN(0 ~ 2^32-1),且段中第一个8位字节从 ISN+1 开始。
- SYN控制位!=1,表示段中第一个8位字节的序号。
2. Ack(Acknowledgment number)
确认号,跟踪已接收的数据,解决丢包问题。
- ACK控制位=1,表示已经接收的8位字节的序号(不包括当前序号),即希望接受的下一个序列号
我们来看下 rfc793 的描述。
简单理解就是:
- Ack = 上一条收到的Seq+length
- Seq = 上一条发送Seq+length
针对SEQ序号,有个比较有意思的是:
SYN 的 Segment 里,第一个字节从 ISN+1 开始,
其实可以间接的理解成 SYN Segment 也占一个字节的数据。那么接收方回复的 ACK 就是上一条的 Seq+1。
三次握手示例
我们通过wireshark
的一次抓包,来分析一下seq
和ack
。
- C —> S:SYN=1,seq=1296494712,len=0
- S —> C:SYN ACK=1,seq=3037568749,ack=1296494713,len=0
- C —> S:ACK=1,seq=1296494713,ack=1296494750,len=0
- C —> S:PSH ACK=1,seq=1296494713,ack=3037568750,len=106
- S —> C:PSH ACK=1,seq=3037568750,ack=1296494819,len=254
参考链接
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章