MST

星途 面试题库

面试题:网络编程中TCP协议三次握手的底层实现细节

请详细描述TCP协议三次握手在TCP/IP协议栈底层是如何实现的,包括涉及到的关键数据结构和函数调用过程。
15.0万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

1. 关键数据结构

  • TCP 控制块(TCB, Transmission Control Block)
    • 每个 TCP 连接在内核中都有一个对应的 TCB,它存储了该连接的所有状态信息,比如源 IP 地址、目的 IP 地址、源端口号、目的端口号、发送和接收的序列号、窗口大小等。在 Linux 内核中,struct sock 结构是与套接字相关的通用数据结构,struct tcp_sock 是基于 struct sock 专门为 TCP 协议扩展的结构,包含了 TCP 连接特有的信息,例如 tcb->snd_nxt 表示下一个要发送的序列号,tcb->rcv_nxt 表示期望接收的下一个序列号。
  • TCP 头部(TCP Header)
    • 是 TCP 数据包的重要组成部分,长度通常为 20 字节(不包含选项字段)。包含源端口号(16 位)、目的端口号(16 位)、序列号(32 位)、确认号(32 位)、数据偏移(4 位,指示 TCP 头部长度,以 4 字节为单位)、保留位(6 位)、标志位(6 位,如 SYN、ACK、FIN 等)、窗口大小(16 位)、校验和(16 位)、紧急指针(16 位,仅当 URG 标志位被置位时有效)。在网络传输过程中,TCP 头部携带了连接建立、数据传输和连接终止等关键信息。

2. 三次握手过程在底层的实现

  1. 第一次握手(客户端发送 SYN 包)
    • 当应用层调用 socket() 函数创建一个 TCP 套接字,并调用 connect() 函数发起连接请求时,内核开始处理。
    • 内核在 tcp_v4_connect() 函数中,构建一个 SYN 包。首先填充 TCP 头部,设置源端口号为客户端套接字绑定的端口号,目的端口号为服务器监听的端口号。生成一个初始序列号(ISN,Initial Sequence Number),将 SYN 标志位置 1。
    • 然后通过 IP 层发送该数据包,IP 层会根据目的 IP 地址查找路由表,确定下一跳地址,并封装 IP 头部,最终通过网络接口发送出去。
  2. 第二次握手(服务器接收 SYN 包并回复 SYN + ACK 包)
    • 服务器内核在接收网络接口传来的数据包后,经过 IP 层解包,发现是 TCP 协议且目的端口号与监听端口号匹配,调用 tcp_v4_rcv() 函数处理。
    • 函数检查 TCP 头部,确认 SYN 标志位为 1,生成自己的初始序列号,同时设置确认号为客户端的 ISN 加 1,表示已收到客户端的 SYN 包。然后设置 SYN 和 ACK 标志位,构建 SYN + ACK 包。
    • 同样通过 IP 层封装并发送回客户端。
  3. 第三次握手(客户端接收 SYN + ACK 包并回复 ACK 包)
    • 客户端内核收到服务器的 SYN + ACK 包后,调用 tcp_v4_rcv() 函数处理。检查 TCP 头部,确认 SYN 和 ACK 标志位正确,并且确认号与自己发送的 ISN 加 1 相符。
    • 然后客户端发送 ACK 包,设置确认号为服务器的 ISN 加 1,ACK 标志位置 1。通过 IP 层发送该 ACK 包给服务器。
    • 服务器收到 ACK 包后,连接正式建立,双方可以开始进行数据传输。

3. 函数调用过程总结

  • 客户端
    • socket() 创建套接字 -> connect() 发起连接 -> tcp_v4_connect() 构建并发送 SYN 包 -> tcp_v4_rcv() 处理服务器的 SYN + ACK 包 -> 构建并发送 ACK 包。
  • 服务器
    • socket() 创建套接字 -> bind() 绑定地址和端口 -> listen() 监听连接 -> tcp_v4_rcv() 处理客户端的 SYN 包 -> 构建并发送 SYN + ACK 包 -> tcp_v4_rcv() 处理客户端的 ACK 包,连接建立。