TCP

TCP头部格式

四元组(源地址,源端口,目的地址,目的端口)可以唯一的确定一个连接。
源地址和目的地址的字段(32 位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。
源端口和目的端口的字段(16 位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。
(图源小林coding
图片损坏

三次握手与四次挥手

三次握手和四次挥手 | 星落溪桥 (xlxq.fun)

滑动窗口

滑动窗口的基本概念

滑动窗口是一种流量控制机制,主要目的是控制发送方可以发送而不需要等待确认(ACK)的最大字节数量。窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。发送窗口和接收窗口分别位于发送方和接收方:

  • 发送窗口:发送方可以在没有接收方确认的情况下连续发送的数据量。
  • 接收窗口:接收方通知发送方自己能够接收的最大数据量,以避免自身缓冲区溢出。

滑动窗口的工作原理

滑动窗口机制的工作过程可以分为以下几个步骤:

  1. 初始化窗口:发送方初始化发送窗口,初始窗口大小根据网络情况和协议规定设定。
  2. 数据发送:发送方在窗口范围内发送数据,每发送一个数据段(Segment)会占用窗口中的一个位置。
  3. 确认ACK:接收方接收到数据后,会返回一个确认包(ACK),表示已经成功接收到数据,并告知发送方可以接收更多的数据。
  4. 窗口滑动:当发送方收到接收方的ACK后,会移动窗口,使得更多的数据可以被发送。这一过程称为窗口的“滑动”。
  5. 可用窗口大小计算:有两个指针分别指向发出但未收到确认的第一个字节、未发送但可发送范围的第一个字节的序列号,通过这两个指针所在位置以及当前滑动窗口大小可以计算得到当前可用的窗口大小(还可以发多少)

窗口大小调整

通常窗口的大小是由接收方的窗口大小来决定的。TCP 头里有一个字段叫 Window,也就是窗口大小。这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据,于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
TCP的窗口大小并不是固定不变的,主要有以下几种情况会导致窗口大小的变化:

  • 流量控制(Flow Control):接收方通过调整窗口大小来控制发送方的发送速率,防止接收方缓冲区溢出。
  • 拥塞控制(Congestion Control):发送方根据网络拥塞情况调整窗口大小,防止网络过载。主要包括以下几种算法:
    • 慢启动(Slow Start):初始窗口大小较小,随着每次成功的ACK,窗口指数级增长。
    • 拥塞避免(Congestion Avoidance):在慢启动阈值(ssthresh)后,窗口线性增长,以避免拥塞。
    • 快速重传(Fast Retransmit):当检测到丢包时,立即重传未确认的数据包。
    • 快速恢复(Fast Recovery):在快速重传后,窗口减半,但不回到慢启动状态,而是进入拥塞避免状态。

重传机制

超时重传

超时重传(Timeout Retransmission) 是当发送方发送一个数据包后没有在指定的时间内收到相应的ACK确认时,会认为数据包可能已经丢失,于是重新发送该数据包的机制。

  • 超时计时器(RTO, Retransmission Timeout):每个未确认的数据包都有一个对应的计时器,如果在计时器到期前没有收到ACK,就会触发重传。
  • 动态调整:RTO的设置通常是动态的,根据网络的往返时间(RTT, Round-Trip Time)不断调整,以适应当前网络状况。超时重传时间 RTO 的值应该略大于报文往返 RTT 的值
  • 超时重传过程
    1. 发送方发送数据包并启动RTO计时器。
    2. 如果在RTO时间内收到ACK,重置计时器。
    3. 如果未收到ACK,RTO计时器到期后重传数据包,并重置RTO计时器。如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。

快速重传

快速重传(Fast Retransmit) 是在没有等待RTO超时的情况下,通过接收方的重复ACK来快速检测并重传丢失的数据包。

  • 重复ACK:如果接收方收到的一个数据包超出预期顺序,就会立即发送一个重复的ACK来确认最后一个按序收到的数据包。
  • 快速重传过程
    1. 发送方发送数据包。
    2. 接收方发现数据包丢失,发送重复ACK。
    3. 当发送方连续收到三个重复ACK(表示网络中的一个数据包很可能丢失),立即重传丢失的数据包,而不等待RTO计时器到期。

SACK(选择性确认)

SACK(Selective Acknowledgment) 是一种TCP扩展, 在TCP 头部选项字段里加一个 SACK ,通过允许接收方告知发送方已正确接收到的非连续数据块,从而提高了数据重传的效率。

  • 传统ACK问题:传统的TCP只允许接收方确认按序接收的数据,这在高丢包率环境下效率较低。
  • SACK的优点:SACK使得接收方可以告诉发送方哪些具体的数据块已经成功接收,这样发送方只需重传那些丢失的数据块,而不是整个数据窗口。
  • SACK选项:在TCP首部中加入SACK选项,包含已接收的非连续数据块的范围。
  • SACK过程
    1. 接收方接收到数据包,使用SACK选项通知发送方已接收的数据块。
    2. 发送方根据SACK信息,选择性重传未确认的数据块,提高重传效率。

D-SACK(重复选择性确认)

D-SACK(Duplicate Selective Acknowledgment) 是SACK的一种扩展,用于检测并处理冗余重传的情况。

  • 冗余重传问题:在某些情况下,发送方可能会不必要地重传已经成功接收的数据块,导致网络资源浪费。
  • D-SACK功能:接收方使用D-SACK通知发送方已接收到重复的数据块,帮助发送方识别和调整重传策略。
  • D-SACK过程
    1. 接收方收到重复数据包,使用D-SACK选项通知发送方重复接收的数据块。
    2. 发送方根据D-SACK信息,调整重传逻辑,避免不必要的重传,提高传输效率。

流量控制

在TCP连接中,发送方和接收方通过滑动窗口协议进行数据传输。接收窗口是接收方通告给发送方的一个值,表示接收方当前可以接收的数据量。发送方根据这个窗口大小调整发送数据的速率,从而防止接收方的缓冲区溢出。

流量控制的工作原理

TCP流量控制的工作机制如下:

  1. 初始连接:在TCP三次握手过程中,双方会交换初始接收窗口大小。
  2. 数据传输
    • 发送方在发送数据时,会根据接收方通告的窗口大小控制发送的数据量。
    • 每当接收方收到数据并成功处理后,会更新接收窗口大小,并在ACK报文中通知发送方。
  3. 窗口滑动:随着数据的发送和接收,窗口会不断滑动,表示新的数据可以被发送和接收。

流量控制过程详解

  1. 发送方初始化窗口:发送方根据接收方在三次握手中通告的初始窗口大小,开始发送数据。
  2. 接收方处理数据
    • 接收方处理并缓存接收到的数据,同时更新接收窗口大小。
    • 接收窗口大小由接收方的缓冲区空间决定,接收方需要保证不会因为数据过多而导致缓冲区溢出。
  3. ACK和窗口更新
    • 接收方发送ACK报文,确认已成功接收到的数据,并在报文中包含当前的接收窗口大小。
    • 发送方根据接收方通告的窗口大小调整接下来的数据发送量。
  4. 窗口关闭和打开
    • 如果接收方的缓冲区已满(或可用窗口太小),接收窗口大小会变为零,此时发送方必须停止发送数据,直到接收方通告新的窗口大小。
    • 当接收方处理完部分数据并释放缓冲区空间后,会发送一个更新窗口大小的ACK报文,通知发送方可以继续发送数据。

流量控制的优势

  • 避免丢包:通过控制发送数据的速率,避免了接收方缓冲区溢出,从而减少了数据包的丢失。
  • 提高传输效率:动态调整发送速率,使得数据传输更加高效,充分利用了网络资源。
  • 适应网络变化:流量控制机制能够根据网络状况和接收方的处理能力,实时调整数据发送速率。

拥塞控制

一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大…拥塞控制目的就是避免发送方的数据填满整个网络。

慢启动

慢启动是TCP在建立连接或检测到网络拥塞后,初始阶段使用的一种算法。其目的是逐步增加发送窗口大小,以避免突然向网络注入大量数据。

  1. 初始状态:发送方初始化拥塞窗口(cwnd)为一个较小的值,通常为1个MSS(最大报文段大小)。
  2. 指数增长:每当收到一个ACK确认,cwnd增加一个MSS。结果是每轮RTT(Round-Trip Time)后,cwnd的大小翻倍。
  3. 达到阈值:当cwnd达到一个预定义的慢启动阈值(ssthresh)时,慢启动阶段结束,进入拥塞避免阶段。

拥塞避免

拥塞避免算法在慢启动结束后,通过线性增长的方式逐步增加cwnd,以避免网络拥塞。

  1. 线性增长:每个RTT结束时,cwnd增加一个MSS/cwnd的大小。
  2. 检测拥塞:如果检测到数据包丢失(通过超时或三次重复ACK),认为发生了拥塞,调整ssthresh并重新进入拥塞控制阶段,即cwnd充重置为1。

快速重传

快速重传是TCP在收到三个重复ACK(即相同的ACK连续三次出现)后,立即重传丢失的数据段,而不等待重传超时(RTO)到期。

  1. 重复ACK:接收方收到乱序数据段后,发送重复ACK。
  2. 触发重传:发送方在收到三个重复ACK后,立即重传丢失的数据段。
  3. 进入快速恢复:重传后,进入快速恢复阶段。

快速恢复

快速恢复算法在快速重传后,避免重新进入慢启动阶段,而是通过调整cwnd和ssthresh,快速恢复数据传输。

  1. 调整cwnd和ssthresh:检测到丢包后,ssthresh设置为cwnd的一半,cwnd设置为ssthresh+3个MSS。
  2. 拥塞避免模式:进入拥塞避免模式,通过线性增长cwnd进行数据传输。
  3. 恢复正常:当新的ACK确认所有丢失的数据段后,cwnd恢复到ssthresh,继续正常传输。

UDP

UDP头部格式

(图源小林coding
图片损坏

TCP和UDP对比

一句话总结方便记忆:
TCP面向连接,保证可靠性,面向字节流,头部20字节,只支持一对一连接,有拥塞控制等多种机制保证不丢失,不重复,不乱序,适用于需要可靠传输的场景;
UDP面向无连接,不保证可靠性,面向报文,头部8字节,支持各种连接,无状态,适用于对传输速度和实时性要求较高,但对数据丢失不敏感的场景。

  1. 连接方式:TCP是面向连接的协议,在数据传输前,必须建立一个稳定的连接(通过三次握手机制),传输结束后需要拆除连接(通过四次挥手机制)。而UDP是无连接的协议,数据传输前不需要建立连接,直接将数据发送给接收方。
  2. 可靠性:TCP提供可靠的数据传输,它通过序列号、确认应答(ACK)、超时重传、流量控制、拥塞控制等机制保证数据的完整性和正确顺序,保证无差错、不丢失、不重复、并且按序到达。而UDP不保证数据传输的可靠性,它不提供序列号、确认应答、重传机制,因此数据可能会丢失、重复或乱序。
  3. 数据传输方式:TCP是面向字节流的数据传输,数据被分割成段(segment),每个段都被序列化和确认。而UDP是面向数据报的数据传输,数据被封装成独立的报文(datagram),每个报文都是一个完整的单元。
  4. 传输效率:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多。
  5. 首部开销:TCP首部较大,最小为20字节,包含序列号、确认号、窗口大小等控制信息。而UDP首部较小,为8字节,仅包含源端口、目的端口、长度和校验和。
  6. 是否提供广播或多播服务:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
  7. 是否有状态:这个和上面的“是否可靠传输”相对应。TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了。
  8. 使用场景:TCP适用于需要可靠传输的场景,如文件传输(FTP)、电子邮件(SMTP)、网页浏览(HTTP/HTTPS)等。而UDP适用于对传输速度和实时性要求较高,但对数据丢失不敏感的场景,如视频流(VoIP)、在线游戏、DNS查询、广播和组播等。