TCP 处于七层网络模型(应表会传网数物)中的传输层。

特点

面向连接

和 UDP 不一样,TCP 传输数据前需要先建立 TCP 连接(此处引出三次握手、四次挥手)。而 UDP 传输数据前不需要建立连接,也不保证可靠传输。

可靠传输

TCP 保证传输的数据:无差错、不丢失、不重复、 按序到达

全双工

通信双方任何时候都能相互通信。并且都有发送缓存、接受缓存。

面向字节流

虽然应用层和 TCP 的交互是一次一个数据块(大小不等),但是 TCP 把这些数据看成仅仅是一连串的无结构字节流。TCP 并不知道所传送的字节流的含义。传输过程如下:

tcp 面向流的概念

这里看到,应用层发送其实不是同步发送的,而只是把数据拷到 TCP 发送缓存里,而下一步如何发送,如何把数据切成报文段,都与应用层无关了。

基于这个字节流传输概念,对于偶尔能听到的 “黏包” 概念也能较为直接的解释。因为 TCP 并没有包的概念,因此自然也就不存在 “黏包” 为什么 TCP 协议有粘包问题。“黏包” 误解的原因是:“应用层协议没有使用基于长度或者基于终结符的消息边界,导致多个消息的粘连”

报文段、字节流

TCP 存在一个 “报文段” 的概念,这个指的是:在 TCP 接收到应用层写入的数据之后,会暂存到发送缓存。而 TCP 在发送数据之前,会从发送缓存中取出一部分数据,并且加上 TCP 层的特定头部数据,再往下传输给 IP 层,加上了 TCP 头部的这部分数据,叫做 TCP 的 “报文段”,这个报文段的最大长度叫做 MSS(最大报文段长度)。而在传输时,报文段会被以字节流的形式进行传输,接收方收到字节流之后,再解析字节流还原成报文段,交付使用。

可靠传输(滑动窗口)

TCP 使用 滑动窗口 来实现可靠传输。TCP 的滑动窗口是以字节为单位的,并对窗口内的字节进行编号,如果窗口内某个低序号的字节未收到确认消息,那么滑动窗口将不会往后移,而会在确认超时之后,重新传送,即 超时重传。这时候,就有可能出现,一条 TCP 链接,某个时刻发生了超时重传,其他数据必须等这个重传恢复之后,才能继续发送。而 HTTP/3 使用的 QUIC 协议使用了多路流复用,同一个传输通道可以同时传输多路流,而不同流也使用不同的流量控制、滑动窗口等,这样即使某一路的流阻塞了,也不会影响其他路的流。

流量控制

流量控制(flow control) 的作用是让发送方的发送速率不要太快,要让接收方来得及接受。

当 TCP 端点 A 向 TCP 端点 B 发送数据时,整个过程会出现两个滑动窗口,A 的发送窗口和 B 的接收窗口。当 B 感受到压力过大,或者其他原因需要进行流控时,会给发送方发送消息,告知发送方 接收窗口(rwnd) 的大小,发送方根据这个数值,调整发送窗口的大小。利用滑动窗口机制可以方便的在 TCP 连接上实现对发送方的流量控制。

拥塞控制

当网络阻塞,例如:链路传输速率只有 10Gb/s ,但是有 100 台计算机,同时以 1Gb/s 的速率传输,这时候就会发生拥塞,导致网络性能变坏,因此需要拥塞控制,防止过多的数据注入到网络中,避免网络中的路由器或者链路过载。拥塞控制有四种算法:慢开始(slow-start)拥塞避免(congestion avoidance)快重传(fast retransmit)快恢复(fast recovery)。 这里网络出现拥塞表现一般为:数据丢失,时延增加,吞吐量下降

慢开始(指数增大)

发送方维护一个拥塞窗口,让发送窗口等于拥塞窗口。最开始把拥塞窗口设为 MSS 大小,每收到一个 ACK,就增加一个 MSS(这里可以看出来,没经过一个传输轮次,拥塞窗口就会加倍)。当拥塞窗口增加到 慢开始门限 之后,改用 拥塞避免算法

拥塞避免(加法增大)

不再每收到一个 ACK 就增加一个 MSS,而是每经过一个 RTT(把发送窗口都发送出去并收到 ACK),增加一个 MSS。当发送方判断网络出现拥塞时,把慢开始门限减为发送窗口的一半,并把拥塞窗口设为 1,重新开始慢开始流程

快重传

首先要求接收方每接收到一个报文段,就发出重复确认,让发送方能尽快重传。接收方收到 3 个重复确认就应该开始重传对方未收到的报文段,而不是等待计时器过期。

快恢复

当发送方收到 3 个重复确认之后,把拥塞控制设置为慢开始门限的一半,然后开始执行拥塞控制算法(加法增大)

结合拥塞控制和流量控制,发送方的发送窗口值为 min(拥塞窗口, 接收窗口)

参考

  • 计算机网络(第六版 谢希仁著)