这张图详细描述了 TCP 握手过程中,从客户端发送 SYN 包到服务器最终建立连接的整个数据流转过程,包括网卡、内核、进程中的各个环节。下面对每个步骤进行详细解释:
客户端到服务器的初始连接请求
- 客户端发送 SYN 包:
- 客户端发起一个 TCP 连接请求,发送 SYN(同步)包到服务器。
- 这个 SYN 包是三次握手的第一步。
网卡驱动
-
进入网卡的 RingBuffer:
- 服务器的网卡接收到来自客户端的 SYN 包,将其存储在网卡硬件的 RingBuffer 中。
- RingBuffer 是网卡内置的一个循环缓冲区,用于暂存接收到的数据包。
-
DMA 传输:
- 网卡使用 DMA(Direct Memory Access)将数据包从 RingBuffer 传输到系统内存中的 DMA 缓冲区。
- DMA 缓冲区位于系统内存,由网卡驱动程序管理。
内核处理
-
硬中断触发:
- 当数据包被 DMA 传输到系统内存后,网卡触发硬中断通知 CPU 数据包已经到达。
- 硬中断处理程序进行基本处理,如记录中断事件,并触发软中断请求。
-
软中断处理:
- 软中断处理程序(如 NAPI 轮询函数)将数据包从 DMA 缓冲区读取,并复制到
sk_buff
结构中。 sk_buff
是内核中用于存储和管理网络数据包的数据结构。
- 软中断处理程序(如 NAPI 轮询函数)将数据包从 DMA 缓冲区读取,并复制到
-
协议栈处理:
- 数据包被存储在
sk_buff
中,并传递给内核的网络协议栈进行处理。 - 在
netif_receive_skb
函数中,数据包根据其协议类型(如 TCP、UDP、ARP 等)被传递到相应的处理函数。
- 数据包被存储在
TCP 三次握手处理
-
进入半连接队列:
- 如果数据包是 TCP SYN 包,它将进入服务器的半连接队列(Syn Queue)。
- 半连接队列用于存储尚未完成三次握手的连接请求。
-
完成三次握手:
- 服务器发送 SYN-ACK 包给客户端,并等待客户端发送 ACK 包以完成三次握手。
- 当服务器接收到客户端的 ACK 包后,连接请求从半连接队列移到全连接队列(Accept Queue)。
进程处理
- 全连接队列:
- 全连接队列用于存储已完成三次握手的连接请求,等待应用层调用
accept
系统调用来处理这些连接。 - 应用程序调用
accept
后,连接从全连接队列移到应用层,正式建立连接,准备进行数据传输。
- 全连接队列用于存储已完成三次握手的连接请求,等待应用层调用
DMA 缓冲区的满情况和处理方法
DMA 缓冲区满的处理
-
数据包丢失:
- 当 DMA 缓冲区满时,新到的数据包无法存储,将被丢弃。这会导致数据包丢失,特别是在高流量情况下。
-
优化措施:
- 增大 DMA 缓冲区:如果硬件允许,可以通过配置或升级网卡来增大 DMA 缓冲区的大小。
- 调整系统参数:优化内核参数,以增加系统缓冲区的容量,提高整体处理能力。
- 使用多队列:配置网卡的多队列机制,使得多个队列可以并行处理数据包,提高处理效率。
- 流量控制:在高流量情况下,使用流量控制和限流机制,减少数据包丢失。
示例命令
-
调整 RingBuffer 和队列大小:
bash复制代码
ethtool -G eth0 rx 4096
-
调整内核参数:
bash复制代码
sysctl -w net.core.rmem_max=26214400 sysctl -w net.core.wmem_max=26214400
-
调整中断亲和性:
bash复制代码
echo 1 > /proc/irq/IRQ_NUMBER/smp_affinity
结论
TCP 握手过程中,数据包从网卡接收到系统内存,再到内核处理的整个过程,涉及硬件(如网卡、RingBuffer、DMA)和软件(如 sk_buff
、协议栈、连接队列)多个层面的协作。DMA 缓冲区在高流量情况下可能会满,通过合理的硬件配置和系统优化,可以提高网络数据包处理能力,减少数据包丢失,保障网络性能。