Skip to content

本模块是公共类课程,适合绝大部分计算机岗位。但部分内容若非前端开发移动端开发客户端(桌面应用、游戏开发)等“大前端”岗位则了解即可。

讲讲 TCP 和 UDP 的区别

TCP(Transmission Control Protocol)和 UDP(User Datagram Protocol)是两种网络传输协议,主要区别如下:

  1. TCP 是面向连接的,UDP 是无连接的:TCP 是面向连接的传输协议,需要先建立连接,然后再传输数据;UDP 是无连接的传输协议,不需要建立连接,直接传输数据。
  2. TCP 是可靠的,UDP 是不可靠的:TCP 是可靠的传输协议,通过重传机制、校验和、滑动窗口等机制保证数据的可靠传输;UDP 是不可靠的传输协议,不保证数据的可靠传输。
  3. TCP 是面向字节流的,UDP 是面向报文的:TCP 是面向字节流的传输协议,将数据看作字节流进行传输;UDP 是面向报文的传输协议,将数据看作报文进行传输。
  4. TCP 是有序的,UDP 是无序的:TCP 是有序的传输协议,保证数据的有序传输;UDP 是无序的传输协议,不保证数据的有序传输。
  5. TCP 是重量级的,UDP 是轻量级的:TCP 是重量级的传输协议,需要建立连接、维护状态、保证可靠传输等;UDP 是轻量级的传输协议,不需要建立连接、不保证可靠传输等。

TCP 和 UDP 的主要区别是连接方式、可靠性、传输方式、有序性和重量级程度,根据不同的需求选择合适的传输协议。

讲讲 TCP 协议的格式

TCP 报文通常由长 20 字节的报文头(不计选项和填充字段的话)和报文体两部分组成。

报文头一般有 5 行,每行 4 个字节,共 20 个字节,包括以下字段:

  1. 第一行:源端口号(16 位):标识发送端的端口号。目的端口号(16 位):标识接收端的端口号。
  2. 第二行:seq 序列号(32 位):用来标识从 TCP 源端向目的端发送的数据字节流,发送数据时,序列号指的是数据的第一个字节的编号。
  3. 第三行:ack 确认号(32 位):是期望收到的下一次数据的第一个字节的序号,确认序号应该是上一次收到的数据字节序号 +1。只有 ACK 标志位为 1 时,确认号字段才有效。
  4. 第四行:Data Offset 数据偏移(4 位):指明 TCP 报文头部的长度,即数据从哪里开始。Reserved 保留位(6 位):保留未来使用,全部置为 0。Flags 标志位(6 位):包括 URG、ACK、PSH、RST、SYN、FIN 等标志位。Window 窗口大小(16 位):窗口大小是指发送端还能接收多少字节的数据。
  5. 第五行:Checksum 校验和(16 位):检验整个 TCP 报文段在传输过程中是否发生变化。Urgent Pointer 紧急指针(16 位):紧急指针是一个偏移量,和序列号相加表示紧急数据的最后一个字节的下一个字节。
  6. (可选)选项和填充字段:TCP 报文头还可以包含一些选项,如最大报文段长度、窗口扩大因子、时间戳等。

报文体是 TCP 报文的数据部分,长度不固定,可以是 0 个字节或多个字节。

讲讲 TCP 三次握手和四次挥手的过程

TCP 三次握手和四次挥手是 TCP 协议中的连接和断开过程,主要过程如下:

  1. 三次握手:

    1. 第一次握手:客户端发送 SYN 包,序列号 seq=x,进入 SYN-SENT 状态。
    2. 第二次握手:服务器收到 SYN 包,发送 SYN+ACK 包,确认号 ack=x+1,序列号 seq=y,进入 SYN-RECEIVED 状态。
    3. 第三次握手:客户端收到 SYN+ACK 包,发送 ACK 包,确认号 ack=y+1,进入 ESTABLISHED 状态。服务端收到 ACK 包,进入 ESTABLISHED 状态。
  2. 四次挥手:

    1. 第一次挥手:客户端发送 FIN 包,序列号 seq=u,进入 FIN-WAIT-1 状态。
    2. 第二次挥手:服务器收到 FIN 包,发送 ACK 包,确认号 ack=u+1,序列号 seq=v,进入 CLOSE-WAIT 状态。客户端收到 ACK 包,进入 FIN-WAIT-2 状态。
    3. 第三次挥手:服务器发送 FIN 包,序列号 seq=w,进入 LAST-ACK 状态。
    4. 第四次挥手:客户端收到 FIN 包,发送 ACK 包,确认号 ack=w+1,进入 TIME-WAIT 状态。间隔 2MSL 后,客户端进入 CLOSED 状态,服务器收到 ACK 包,进入 CLOSED 状态。

TCP 三次握手和四次挥手是为了建立和断开 TCP 连接,保证数据的可靠传输。

为什么四次挥手结尾要等待 2MSL(Maximum Segment Lifetime)

  1. 保证数据的可靠传输:TIME-WAIT 状态是为了保证数据的可靠传输,防止数据丢失或重复传输。
  2. 防止连接的混淆:TIME-WAIT 状态是为了防止连接的混淆,保证连接的唯一性,防止新的连接和旧的连接混淆。
  3. 保证连接的可靠关闭:TIME-WAIT 状态是为了保证连接的可靠关闭,防止连接的不完整,保证连接的完整性。
  4. 防止 TIME-WAIT 状态的冲突:TIME-WAIT 状态是为了防止 TIME-WAIT 状态的冲突,保证连接的唯一性,防止连接的冲突。

因此,四次挥手结尾要等待 2MSL 是为了保证数据的可靠传输,防止连接的混淆,保证连接的可靠关闭,防止 TIME-WAIT 状态的冲突。

讲讲 TCP 的滑动窗口协议流程

TCP 的滑动窗口协议是一种流量控制机制,主要流程如下:

  1. 发送端发送数据:发送端发送数据,接收端接收数据,接收端发送 ACK 包,确认收到的数据。
  2. 接收端发送窗口大小:接收端发送窗口大小,告诉发送端还能接收多少字节的数据。
  3. 发送端调整窗口大小:发送端根据接收端发送的窗口大小调整发送窗口大小,保证发送端和接收端的窗口大小一致。
  4. 循环进行上述流程。

TCP 的滑动窗口协议是为了实现流量控制,保证发送端和接收端的窗口大小一致,防止数据的丢失和重传。

讲讲 TCP 的拥塞控制机制

先说一个名词:拥塞窗口(Congestion Window,cwnd)。拥塞窗口是发送方可以发送的数据量,是动态变化的,取决于网络的拥塞程度。

发送方会让自己的发送窗口大小等于拥塞窗口和接收窗口中的较小值。

实现拥塞窗口动态变化主要有以下几种算法:

  1. 慢启动(Slow Start):发送端拥塞窗口从 1MSS 开始,每收到一个 ACK 包,拥塞窗口大小加 1,指数增长,直到达到慢启动阈值(Slow Start Threshold,ssthresh,一般是 65536)。
  2. 拥塞避免(Congestion Avoidance):发送端拥塞窗口达到慢启动阈值后,拥塞窗口大小线性增长,每个 RTT(往返时间)增加 1 个 MSS,直到检测到网络拥塞。
  3. 快重传(Fast Retransmit):发送端收到 3 个重复的 ACK 包,说明某个数据包丢失,立即重传丢失的数据包,而不是等待超时重传。此时慢启动阈值设置为拥塞窗口的一半,拥塞窗口大小设置为新的慢启动阈值加上 3 个 MSS(因为已经收到三个重复的 ACK 包),重新进入慢启动阶段。

TCP 的拥塞控制机制是为了防止网络拥塞,保证数据的可靠传输,提高网络的性能和可靠性。

说说半连接队列和 SYN Flood 攻击的关系(非“大前端”岗位了解即可)

半连接队列

在 TCP 三次握手前,服务器状态从 CLOSED 变为 LISTEN,此时服务器会创建一个半连接队列(SYN Queue)和一个全连接队列(Accept Queue)。

当客户端发送 SYN 包时,服务器回复 SYN+ACK 包,此时状态变成 SYN-RECEIVED,此时连接就被放入半连接队列中。

当客户端发送 ACK 包时,服务器状态变为 ESTABLISHED,此时连接就被放入全连接队列中。

SYN Flood 攻击

SYN Flood 攻击是一种 DoS/DDoS 攻击,攻击者向服务器发送大量伪造的 SYN 包,服务器向不存在的 IP 回复 SYN+ACK 包,但攻击者不回复 ACK 包,导致服务器的半连接队列被填满,资源耗尽后无法处理正常的连接请求。

解决方案有三种:

  1. SYN Cookies:在服务器资源紧张时,使用 SYN Cookies 技术。服务器收到 SYN 包后,不立即分配资源,而是根据客户端的 SYN 包计算一个 Cookie,放入 SYN 包的序列号中,然后回复 SYN+ACK 包。客户端收到 SYN+ACK 包后,回复 ACK 包时带上 Cookie,服务器根据 Cookie 计算出序列号,验证合法性后才建立连接。这样可以防止半连接队列被填满。
  2. 增加半连接队列大小:增大半连接队列的大小,提高服务器处理能力。
  3. 缩短超时时间,减少重试次数:缩短半连接状态的超时时间,减少重试次数,尽快释放资源。

讲讲 TCP 是如何优化连接建立过程的(非“大前端”岗位了解即可)

TCP 优化连接建立过程主要运用了 TFO(TCP Fast Open)技末。

在首轮握手当中,服务器将计算得来的 SYN Cookie 放入 SYN+ACK 包中 TCP 报文的 Fast Open 字段,客户端收到 Cookie 之后将其缓存下来,后续握手流程照常执行。

但在第二次与服务器建立连接时,客户端发送 SYN 包的同时,就可以将缓存的 Cookie、SYN 和 HTTP 请求一并发送给服务器,在验证合法性之后,服务器正常返回 SYN+ACK 包,此时服务器可以直接发起 HTTP 响应,即便第三次握手可能还没有开始执行。

其重点是,请求在第一次握手时就已经发送,不需要等待第三次握手完成,而响应也可以在第三次握手之前就已经发送,二者互不干扰,从而大大减少了连接建立的时间。