Linux下TCP收包过程

目录

前言

一、涉及的软硬件

二、收数准备

三、数据帧到达

四、数据帧从 卡到Ringbuffer

五、让CPU反应一下

1. 硬中断处理

2. 为啥关闭硬中断

六、从RingBuffer到softnet_data

七、从softnet_data到应用消费队列

1. 连接阶段Socket队列

2. 数据传输阶段Socket队列

八、应用消费数据

总结


前言


一、涉及的软硬件

硬件:多核心CPU,支持多队列的 卡,内存,DMA控制单元

软件:能很好使用上述硬件的CentOS操作系统

二、收数准备

说明 备注
上电启动
操作系统

初始化ksofrirq/x进程

以CPU核心为单位,每个CPU核心一个。该进程处理软中断
络子系统
创建softnet_data数据结构 每个CPU核心一个,数据结构上是一个队列
协议栈注册 OS内核注册ip, tcp , udp数据包的处理函数
卡部分
卡驱动对 卡做基本的初始化
借助DMA控制单元向内存申请RingBuffer存储空间 该RingBuffer数量与 卡配置的接收队列数量一致
卡驱动向软中断向量表注册中断处理poll函数
上述准备完成后, 卡就可以准备接收数据了。

三、数据帧到达

首先在 卡缓存中排队,如果 卡支持数据包合并也会在缓存中做必要的合并,这里的包主要是数据链路层的小包到大包。注意包合并带来的是吞吐量的提升,但可能会造成收包延迟。

如何知道 卡名称p>

ifconfig

该命令可以查看 卡的特性,也可以查看当前MTU,IP地址等信息,不过最关键的还是 卡的设备名称。在后续的一系列命令中,还是要用的。

四、数据帧从 卡到Ringbuffer

卡驱动借助DMA在主存中完成空间分配,并将 卡缓存中的包以DMA方式送入主存的RingBuffer中。前面说到了多队列问题,这里 卡会根据配置计算该送入哪个RingBuffer中。

查看 卡接收队列数量

ethtool  -l 设备名

查看 卡接收队列容量

ethtool -g 设备名

查看 卡特性

ethtool -k 设备名

查看 卡收发流量

sar -n DEV 1

如果RingBuffer空间太小,而对方发送速度很快,就会导致丢包。

在ifconfig命令中体现在 rx_overruns 指标上

在ethtool命令中体现在 rx_fifo_errors 指标上

卡完成数据复制到RingBuffer之后,产生硬中断,通知CPU核心有数据到达,当然也是通知与队列相关的CPU核心。

五、让CPU反应一下

CPU收到硬中断后,向CPU的待处理硬中断设备列表中记录 卡设备 ,并通过 卡驱动关闭硬中断。而后产生软中断,由软中断进程对软中断做进一步的处理。

1. 硬中断处理

硬中断处理分上半场和下半场。上半场记录设备 ,然后关闭硬中断,并产生对应的软中断,至此中断结束。下半场软中断处理才是真正的业务逻辑。总结来说,前者做了分发, 后者完成了真正的工作处理。

2. 为啥关闭硬中断

因为 络数据是源源不断到达,不停地被打断CPU没法专心做其他处理。既然已经中断一次就知道有数据到了,没有必要中断多次。

硬中断查看

cat /proc/interrupts

软中断查看

cat /proc/softirqs

CPU中断和进程亲和性绑定

/proc/irq/IRQ_NUMBER/smp_affinity

多核情况下,如果设置不当,可能存在 卡中断处理不均衡导致数据接收速度缓慢,可以手动均衡中断。也可以运行irqbalance进程让系统自动调整中断分布。

六、从RingBuffer到softnet_data

Ksoftirqd进程找到 卡注册的poll函数从RingBuffer中读取数据,首先转换为skb结构,然后并做必要的包合并,拷贝到softdata_net队列中等待CPU处理。如果队列已满,则会产生丢包,在ifconfig命令中体现在 rx_dropxx 指标上。

查看队列长度,默认为1000

sysctl net.core.netdev_max_backlog

查看队列状态

cat /proc/net/softnet_stat

到这里如果RingBuffer中没有可读数据,默认会再做一次轮训,如果依然没有数据,则调用 卡驱动恢复 卡硬中断。这里再做的一次轮训值得借鉴,可以缓解CPU的中断数量。

七、从softnet_data到应用消费队列

内核从softnet_data中取出数据并通过 络协议栈处理得到应用传输的原始数据,计算目标的Socket,并将其放入目标Socket的消费队列中。OS内核为将Socket分为两大类,一类是连接阶段的Socket,另一类则是数据传输阶段的Socket。显然,前者还处于TCP最开始的三次握手阶段。

1. 连接阶段Socket队列

syn_queue server端已发送syn,等待client ack
accept_queue client ack完成,但尚未被应用调用accept取走

2. 数据传输阶段Socket队列

receive_queue 待应用直接消费的数据
backlog_queue receive_queue满,则放入backlog_queue中
unordered_queue 收到的无序数据包,待重排序后放入前面某个队列中

查看tcp socket和收发队列长度

netstat 

特别地对于listen状态的socket,其Send-Q和Receive-Q代表的值为连接阶段socket相关。

八、应用消费数据

当应用从socketInputStream中读取数据,内核从队列中读取并喂给Java进程,进程完成应用级别的反序列化,完成数据接收。


总结

文章知识点与官方知识档案匹配,可进一步学习相关知识 络技能树首页概览22968 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年6月13日
下一篇 2022年6月13日

相关推荐