TCP 网络控制

文章目录

  • [1 TCP 的特点及目的](#1 TCP 的特点及目的)
  • [2 序列号与确认应答号](#2 序列号与确认应答号)
  • [3 重发超时时间](#3 重发超时时间)
  • [4 连接管理](#4 连接管理)
  • [5 以报文段为单位发送数据](#5 以报文段为单位发送数据)
  • [6 利用窗口控制提高速率](#6 利用窗口控制提高速率)
  • [7 窗口控制与重发控制](#7 窗口控制与重发控制)
  • [8 流量控制](#8 流量控制)
  • [9 拥塞控制](#9 拥塞控制)
  • [10 提高网络利用率的规范](#10 提高网络利用率的规范)
    • [1 Nagle 算法](#1 Nagle 算法)
    • [2 延迟确认应答](#2 延迟确认应答)
    • [3 捎带应答](#3 捎带应答)
  • [11 使用 TCP 的应用](#11 使用 TCP 的应用)

1 TCP 的特点及目的

TCP 与 UDP 不同,TCP "人如其名",可以说是对"传输、发送、通信"进行"控制"的协议。

TCP 的诞生和发展都是为了在互联网上实现可靠的通信。

而随时变化的用户导致互联网上的通信面临各种问题。

TCP 与 UDP 的区别相当大。它充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的数据包进行顺序控制。而这些在 UDP 中都没有。

此外,TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而避免通信流量的浪费。

由于 UDP 没有连接控制,因此即使对端从一开始就不存在或中途退出网络,数据包还是能够发送出去。(有些系统实现了当 ICMP 返回错误时,就不再继续发送的机制。)

TCP 还可以调节数据包的发送数量,避免网络因拥塞而陷入收敛状态。

根据 TCP 的这些机制,在 IP 这种面向无连接的网络上也能够实现高可靠性的通信。

由此可知,TCP 更适用于以下通信场景:

  • 需要可靠的通信时(丢包会引发问题)。
  • 通过互联网传输大量数据时(如文件传输)。
  • 播放如视频点播和直播等对实时性要求不高的视频和音频(音乐)时(流媒体)。
  • 期望在任何规格的线路上都能达到较为合理的通信性能时(宽带 / 窄带、高可靠性 / 低可靠性、MTU 差异等)。

流媒体是一种边下载边播放音视频数据的技术,常用于互联网上的直播。

在 TCP 中,丢包引起的重发处理会导致数据延迟达到几秒甚至几十秒才能到达。

而流媒体通过在播放前设置缓存,可以提前缓存几秒到几十秒的数据,有效防止由于丢包导致的播放中断。

这样一来,即使偶尔发生丢包,流媒体依然可以实现流畅且高质量的音视频播放。

2 序列号与确认应答号

在 TCP 中,当发送端的数据到达接收端主机时,接收端主机会返回一个已经收到消息的通知,这个消息叫作肯定确认应答(ACK)

通常,两个人对话时,可以在对话的停顿处点头或询问以确认对话的内容。

如果对方迟迟没有任何反馈,说话的一方可以再重复一遍以确保对方确实听到了。

因此,对方是否理解了此次对话的内容,对方是否完全听到了对话的内容,都要靠对方的反应来判断。

网络中的"确认应答"其实就类似这样的一个概念。

当对方听懂对话内容时,会说"嗯",这就相当于返回了一个 肯定确认应答(ACK)

而当对方没有理解对话内容或者没有听清时,会问一句"咦?",这好比一个 否定确认应答(NACK)

TCP 通过 肯定确认应答(ACK) 实现可靠的数据传输,如下图所示。
主机B 主机A 主机B 主机A 数据 (1 ~ 1000) 确认应答 ACK (下一个是1001) 数据 (1001 ~ 2000) 确认应答 ACK (下一个是2001)

当发送端将数据发送之后,会等待对端的确认应答。

如果有确认应答,说明数据已经成功到达对端。反之,数据丢失的可能性很大。

如下图所示,在一定时间内没有收到确认应答,发送端就可以认为数据已经丢失了,并进行重发。

由此,即使产生了丢包,仍然能够通过重发保证数据到达对端,实现可靠传输。
主机B 主机A 主机B 主机A 数据在网络中丢失 等待一段时间(重传定时器) 数据 (1~1000) 重发数据 (1~1000) 确认应答 ACK (下一个是1001)

当数据由主机 A 发出后,如果因网络拥塞等原因丢失,该数据将无法到达主机 B。

此时,如果主机 A 在一个特定的时间间隔内未收到主机 B 发来的确认应答,主机 A 将会对此数据进行重发。

未收到确认应答并不意味着数据一定丢失了,也有可能是对方已经收到了数据,只是返回的确认应答在途中丢失。

这种情况也会导致发送端没有收到确认应答,从而认为数据没有到达目的地,并再次发送数据。
主机B 主机A 主机B 主机A ACK 在网络中丢失 等待一段时间(重传定时器) 数据 (1~1000) ACK (1001) 重发数据 (1~1000) ACK (1001)

此外,也有可能因为一些其他原因导致确认应答延迟到达,在源主机重发数据之后才到达的情况也屡见不鲜。

此时,源主机只要按照机制继续发送数据即可。

但是对于目标主机来说,这简直是一种"灾难"。

它会反复收到相同的数据,为了对上层应用程序提供可靠的传输,目标主机必须放弃重复的数据包。

为此,必须引入一种机制,它既能够识别数据是否已经被接收,又能够判断是否需要接收数据。

上述这些确认应答处理、重发控制以及重复控制等功能可以通过序列号来实现。

序列号是一种按照顺序为发送数据的每一个字节(8 位字节)都标上号码的机制。

提示

TCP 的序列号并不是从 0 开始,而是在连接建立时随机生成一个初始序列号(ISN),之后按照每发送一个字节递增。

接收端通过查询接收数据的TCP 首部中的序列号和数据长度,将自己下一步应该接收的序列号作为确认应答返回。

就这样,通过 序列号和确认应答号,TCP 可以实现可靠传输。

3 重发超时时间

重发超时是指在重发数据之前,等待确认应答到来的特定时间间隔。

如果超过了这个时间间隔仍未收到确认应答,发送端将进行数据重发。

最理想的情况是,找到一个最小时间,使得"确认应答一定能在这个时间段内返回"。

然而,这个时间的长短会随着数据包途经的网络环境不同而有所变化。

例如,在高速的局域网中,时间间隔相对较短,而在长距离的通信中,时间间隔应该比局域网中要长一些。

即使是在同一个网络中,根据不同时段的网络拥塞程度,时间间隔的长短也会发生变化。

TCP 要求不论处在何种网络环境中,都要提供高性能通信,并且无论网络拥塞情况发生何种变化,都必须保持这一特性。

为此,它在每次发送数据时都会计算往返时间及其偏差

将往返时间和偏差相加,重发超时的时间就是比这个总和要稍大一点儿的值。

重发超时的计算既要考虑往返时间 又要考虑偏差是有原因的。

网络环境的不同可能会导致往返时间产生大幅波动,这是因为数据包可能会经过不同的路径到达目的地。

TCP/IP 的目的,是即使在这种环境中也要进行控制,尽量不要无谓地进行数据重发。
主机B 主机A 主机B 主机A 开始测量RTT 计算往返时间RTT 再次测量RTT 更新RTT与偏差 根据 RTT+偏差 计算新的重传超时(RTO) 数据 确认应答 数据 确认应答 数据 确认应答

偏差值较小时:

偏差值较大时:

在 BSD 的 UNIX 以及 Windows 系统中,由于超时都以 0.5 秒 为单位进行控制,因此重发超时都是 0.5 秒的整数倍。

不过,由于最初的数据包还不知道往返时间,所以 重发超时一般设置为 6 秒左右。

数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会呈指数(型)增长。

此外,数据也不会被无限、反复地重发。达到一定重发次数后,如果仍没有任何确认应答返回,系统将认为网络或对端主机发生了异常,强制关闭连接,并通知应用程序通信异常终止。


4 连接管理

TCP 提供面向有连接的通信传输。

面向有连接是指在数据通信开始之前,先做好通信两端之间的准备工作,而在结束数据通信之前要先发送相应的信号。

UDP 是一种面向无连接的通信协议,它不会检查对端是否可以通信,而是直接将 UDP 数据包发送出去。

TCP 与此相反,它会在数据通信之前,通过发送一个 SYN 数据包(只包含 TCP 首部)作为建立连接的请求,并等待确认应答。

TCP 中发送第一个 SYN 数据包的一方叫作 客户端 ,接收这个数据包的一方叫作 服务端

如果对端发来确认应答,则认为可以进行数据通信。如果对端的确认应答未能到达,就不会进行数据通信。

此外,在通信结束时,TCP 还会进行断开连接的处理(FIN 数据包),如下图所示。
主机B(服务端) 主机A(客户端) 主机B(服务端) 主机A(客户端) 连接建立(三次握手) 连接建立完成,开始通信 连接断开(四次挥手) SYN(请求建立连接) ACK、SYN(针对SYN的确认应答、请求建立连接) ACK(针对SYN的确认应答) 数据 ACK 数据 ACK FIN(请求断开连接) ACK(确认FIN) FIN(请求断开连接) ACK(确认FIN)

可以使用 TCP 首部中用于控制的字段来管理 TCP 连接。

一个连接的建立与断开,正常情况下至少需要来回发送 7 个数据包 才能完成。

5 以报文段为单位发送数据

在建立 TCP 连接的同时,还可以确定发送数据包的单位,我们可以称其为"最大报文段长度"(MSS:Maximum Segment Size)。

最理想的情况是,最大报文段长度正好是 IP 中不会被分片处理的最大数据长度。

TCP 在传送大量数据时,以 MSS 的大小将数据进行分片发送,进行重发时也是以 MSS 为单位的。

MSS 是在 3 次握手时,在两端主机之间被计算得出的。

两端的主机在发出建立连接的请求时,会在 TCP 首部中写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 的大小。

然后,双方会在彼此的 MSS 选项中选择一个较小的值投入使用,如下图所示。

图中的数字表示数据报的长度,单位为 8 位字节。确认应答的报文段有一部分已省略。

为了附加 MSS 选项,TCP 首部将不再是 20 字节,而是 4 字节的整数倍。

在建立连接时,如果一方的 MSS 选项被省略,可以选 IP 包的长度不超过 576 字节的值(IP 首部 20 字节、TCP 首部 20 字节,MSS 为 536 字节)。

6 利用窗口控制提高速率

TCP 以一个报文段为单位,每发送一个报文段就进行一次确认应答的处理,如下图。

这样的传输方式存在一个缺点,那就是报文段的往返时间越长,通信性能就越低。

为了解决这个问题,TCP 引入了 窗口(Window) 这个概念。

通过窗口机制,即使在往返时间较长的情况下,TCP 也能够保持较高的通信效率。

在窗口机制下,发送端主机不再以每个报文段为单位等待确认应答,而是可以连续发送多个报文段。

也就是说,发送端主机在发送了一个报文段之后,不必一直等待确认应答,而是可以继续发送后续的数据。

窗口大小是指 无需等待确认应答即可继续发送数据的最大值,再上图中,窗口大小为 4 个报文段。

这种机制通过使用大量的 缓冲区(Buffer),实现了对多个报文段同时进行确认应答的功能。

如图所示,发送数据中被方框圈起来的部分正是前文所述的窗口。

在窗口内的数据,即使没有收到确认应答也可以被发送出去。

不过,在整个窗口的确认应答没有到达之前,如果其中部分数据出现丢包,那么发送端要负责重发这些数据。

为此,发送端主机需要设置缓冲区来保留这些待重发的数据,直到收到它们的确认应答。

滑动窗口以外的部分包括尚未发送的数据及已确认对端已经收到的数据。

当数据发出并如期收到确认应答后,就可以不用再重发,此时可以将数据从缓冲区清除。

在收到确认应答的情况下,将窗口滑动到确认应答中指定的序列号的位置,到该序列号为止的数据将被移出窗口。

这样可以按顺序将多个报文段同时发送,从而提高通信性能,这种机制也被称为滑动窗口控制。

7 窗口控制与重发控制

在使用窗口控制时,如果出现报文段丢失该怎么办呢?

首先,我们考虑确认应答未能返回的情况。

在这种情况下,由于数据已经到达对端,因此不需要再进行重发。

然而,在没有使用窗口控制时,没有收到确认应答的数据都会被重发。

而在使用了窗口控制时,某些确认应答即使丢失也无需重发。

其次,我们来考虑一下某个报文段丢失的情况。

接收端主机如果收到一个自己应该接收的序列号以外的数据,会针对当前为止收到的数据返回确认应答。

当窗口大到一定程度时,即使有少部分的确认应答丢失也不会进行数据重发。

可以通过下一个确认应答进行确认。

如下图所示,当 1001~2000 这一报文段丢失后,发送端会一直收到序列号为 1001 的确认应答。

这个确认应答实际上是在提醒发送端:"我想接收的是从 1001 开始的数据"。

因此,在窗口比较大,又出现报文段丢失的情况下,同一个序列号的确认应答会被重复返回。

发送端如果连续 3 次收到同一个确认应答,就会将其所对应的数据进行重发。

由于这种机制比之前提到的超时管理 更高效,因此也被称作 高速重发控制(Fast Retransmit)

8 流量控制

发送端根据自己的实际情况发送数据。

但是,如果不顾接收端的实际接收能力,向其发送了大量数据包,加之接收端在处理其他问题上又要花费一些时间,最终可能会导致接收端在高负荷的情况下无法接收全部数据。

如此一来,如果接收端将本应该接收的数据丢弃,那么就会触发重发机制,从而导致网络流量的浪费。

为了防止这种现象的发生,TCP 提供一种机制,可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是所谓的流量控制

它的具体操作是,接收端主机通知发送端主机自己可以接收数据的大小,于是发送端主机发送不超过这个限度的数据。

该限度大小被称作窗口大小,窗口大小的值就是由接收端主机决定的。

在 TCP 首部中,专门有一个字段用来通知窗口大小。

接收端主机会将自己可用于接收数据的缓冲区大小放入这个字段中,并将其通知给发送端。

这个字段的值越大,说明网络的吞吐量越高。

不过,接收端的缓冲区一旦面临数据溢出,窗口大小的值将会随之被设置为一个更小的值,并将其通知给发送端,从而控制数据发送量。

也就是说,发送端主机会根据接收端主机的指示,对发送数据的量进行控制,这就形成了一个完整的 TCP 流量控制。

如上图所示,当接收端的接收到从序号 3001 开始的报文段后,缓冲区已满,接收端将不得不暂时停止接受数据。

同时,缓冲区被占满 时,接收端会将窗口大小通告为 0,此时发送端将停止发送数据。

如果之后接收端释放了一部分缓冲区并发送 窗口更新通知,但该通知在网络中丢失,那么发送端可能一直认为窗口大小仍然为 0,从而导致通信停滞。

为了解决这个问题,TCP 引入了 窗口探测(Window Probe)

  • 发送端会周期性发送一个探测报文段
  • 报文段只包含 1 字节数据
  • 目的:获取接收端最新的窗口大小

如果接收端窗口已经恢复,就会在确认应答中返回新的窗口大小,从而恢复数据传输。

9 拥塞控制

有了 TCP 的窗口控制,发送端主机即使还没处理来自接收端的确认应答,也能够连续发送大量数据。

然而,如果在通信刚开始时就发送大量数据,可能会引发其他问题。

一般来说,计算机网络处在一个共享的环境中,所以有可能会因为其他主机之间的通信导致网络拥堵。

在网络出现拥堵时,如果突然发送一组较大的数据,极有可能导致整个网络的瘫痪,从而影响到网络中的其他用户。

当网络因拥堵而难以通信时,称为 拥塞

网络拥堵时常发生,尤其是在互联网环境中。

如果拥塞状态持续时间过长,甚至无法继续进行正常通信。

TCP 为了防止该问题的发生,在通信一开始时会通过一个叫作 慢启动(Slow Start) 的算法得出的值,对发送数据量进行控制。

因此,在刚开始通信时,TCP 数据包的收发情况如下图所示。

最初将发送端的窗口(拥塞窗口)设置为 1,每收到一个确认应答,窗口的值就增加 1 个报文段。

由于图中所示为没有延迟确认应答的情况,因此与实际情况有所不同。

为了在发送端调节所要发送数据的量,定义了一个叫作 "拥塞窗口" 的概念。

于是,在慢启动时,先将拥塞窗口的大小设置为 1 个报文段(1 MSS),再发送数据。

之后每收到一次确认应答(ACK),拥塞窗口的值就加 1。

如果建立连接以后即从 1 MSS 开始进行慢启动,在通过卫星等方式通信时,提高通信吞吐量所需的时间会比较长。

因此,有时会将慢启动的初始值设为大于 1 MSS 的值。

具体来说,当 MSS 的值小于 1095 字节时,最大初始值为 4 MSS;

当 MSS 的值超过 2190 字节时,最大初始值不小于 2 MSS。

在发送数据包时,将拥塞窗口的大小与接收端主机通知的窗口大小进行比较,然后选择它们当中较小的值,发送比这个较小值还要小的数据量。

当发生超时重发时,TCP 会将拥塞窗口的值设置为 1,然后重新开始慢启动。

有了上述这些机制,就可以有效地减少通信开始时的连续发包(Burst)导致的网络拥堵,并且可以避免网络拥塞情况的发生。

不过,随着数据包的往返,拥塞窗口呈指数(型)增长,拥堵状况激增甚至导致网络拥塞的发生。

为了防止这些情况的发生,引入了 "慢启动阈值" 的概念。

只要拥塞窗口的值超过这个阈值,在收到确认应答时,拥塞窗口只能按以下比例进行放大:

  • (1 个报文段的字节数 / 拥塞窗口(字节))× 1 个报文段字节数

拥塞窗口越大,确认应答的数目就会越多。

不过,随着收到确认应答的数目的增加,拥塞窗口的涨幅逐渐减小,甚至小于 1 个报文段的字节数。

因此,拥塞窗口的大小呈直线上升的趋势。

TCP 通信开始时,并没有设置相应的慢启动阈值。

只有在超时重发时,才会将其设置为当时拥塞窗口大小的一半。

由于重复确认应答触发的快速重发与超时重发机制的处理方式略有不同。

前者要求至少 3 个报文段到达发送端主机后才会触发,相比后者,网络拥塞的程度要轻一些。

由重复确认应答进行快速重发控制时,慢启动阈值的大小被设置为当时拥塞窗口大小的一半。

然后,将拥塞窗口的大小设置为该慢启动阈值加 3 个报文段 的大小。

有了这样一种控制机制,TCP 的拥塞窗口如下图所示发生变化。

由于拥塞窗口的大小会直接影响数据转发时的吞吐量,因此一般情况下,拥塞窗口越大,越会形成高吞吐量的通信。

当 TCP 通信开始以后,网络吞吐量会逐渐增大,但是随着网络拥塞的发生,吞吐量会急速减小。

之后会再次进入吞吐量逐渐增大的过程。因此,TCP 的吞吐量特性给人一种逐步占领网络带宽的感觉。

10 提高网络利用率的规范

1 Nagle 算法

为了提高网络的利用率,TCP 实现了一种叫作 Nagle 算法 的算法。

该算法的基本思路是:

如果发送端还有未被确认的小数据包,就先不要立即发送新的小数据,而是将这些小数据先缓存起来,等到累计到一定大小(MSS)或者已发的数据都收到确认应答时,再发送。

这样做的目的,是减少网络中大量微小报文段的出现,降低链路开销,提高网络利用率。

利用这个算法时,会将网络中出现的大量小包进行合并,从而提升效率。

不过,这种做法也会带来一定延迟,因此在对实时性要求较高的场景下,有时并不适合使用 Nagle 算法。

如因"按下按钮"或"转动旋钮"等事件产生的数据,在发送这类小数据包时,是可以禁用 Nagle 算法的。


2 延迟确认应答

接收数据的主机如果每次都立即回确认应答,则可能会返回一个较小的窗口。

这是因为刚接收完数据,缓冲区已满。

当发送端收到这个小窗口的通知以后,会以它为上限发送数据,从而降低了网络的利用率。

为此,引入了一种方法,那就是接收端收到数据以后并不立即返回确认应答,而是延迟一段时间。

  • 在没有收到 2 × 最大报文段长度 的数据之前不做确认应答(根据操作系统的不同,有时也有不论数据大小,只要收到两个数据包就返回回确认应答的情况)。
  • 其他情况下,最多延迟 0.5 秒 发送确认应答(很多操作系统设置为 0.2 秒左右,时间越短 CPU 负载越低)。

事实上,不必为每个报文段都进行一次确认应答。

由于 TCP 采用滑动窗口的控制机制,因此通常情况下,确认应答的次数少一些也无妨。

在 TCP 文件传输中,绝大多数情况下是每两个报文段返回一次确认应答。

3 捎带应答

有些应用层协议发送的消息到达对端后,对端会对其进行处理,并返回一个回执。

例如,电子邮件协议的 SMTP 或 POP、FTP 中的连接控制部分等。

如下图所示,这些应用层协议使用同一个连接进行数据的交互。

即使是在 Web 中使用的 HTTP,从 1.1 版以后也是如此。

再例如,远程登录中针对输入的字符进行回送校验,也是对发送消息的一种回执。

回送校验是指在远程登录中,在键盘上输入的字符到达服务器以后再返回来显示给客户端。

在此类通信中,TCP 的确认应答和回执数据可以通过一个数据包发送。

这种方式叫作 捎带应答(Piggyback Acknowledgement)

通过这种方式,可以使收发的数据量减少。

另外,如果接收数据以后立即返回确认应答,则无法实现捎带应答。

除非从将所接收的数据传给应用程序处理开始,到应用程序生成返回数据并准备发送为止,一直延缓确认应答的发送。

也就是说,如果没有启用延迟确认应答,就无法实现捎带应答。

延迟确认应答是一种能够提高网络利用率,从而降低计算机处理负荷的较优处理机制。

11 使用 TCP 的应用

TCP 使用各种各样的控制机制。甚至它还会使用一些本文中未提及的其他更复杂的控制机制。

不过,这些控制机制有时会受到一定缺陷的困扰。

因此,在开发应用程序时,有必要考虑一下是全权交给 TCP 去处理,还是由应用程序自己进行更细微的控制。

相关推荐
%重启试试吧2 小时前
网络管控协议
网络
乾元2 小时前
红队测试:如何对大模型进行系统性的安全红队评估
运维·网络·人工智能·神经网络·安全·网络安全·安全架构
@insist1232 小时前
数据库工程师核心 TCP/IP 协议栈知识:从软考考点到运维实战
运维·数据库·网络协议·tcp/ip·软考·数据库系统工程师·软件水平考试
茶杯梦轩2 小时前
HTTP核心:协议、状态码与请求方法详解
后端·网络协议·面试
上海云盾-小余2 小时前
端口扫描防御实战:一招识别攻击前兆,筑牢网络第一道屏障
网络
gfdhy2 小时前
【Linux】服务器网络与安全核心配置|静态IP+SSH加固+防火墙,公网服务器必学实操
linux·服务器·网络·tcp/ip·算法·安全·哈希算法
somi72 小时前
Linux-网络通信02-UDP 与 TCP Socket
linux·网络·udp·tcp
Hello World . .3 小时前
Linux:网络编程-UDP通信
linux·网络·udp
努力搬砖的鱼3 小时前
校园网运维-生成树协议实战
运维·网络