0

0

Linux 网络栈的基本结构

舞姬之光

舞姬之光

发布时间:2026-01-25 18:52:02

|

764人浏览过

|

来源于php中文网

原创

Linux内核网络栈分为链路层、网络层、传输层、套接字层四层;每层通过sk_buff指针操作实现零拷贝,依赖struct sock标识连接,驱动经NAPI或中断将包送入netif_receive_skb()启动协议处理。

linux 网络栈的基本结构

Linux 网络分哪几层?不是 OSI,是内核实际跑的四层

Linux 内核网络栈按功能划分为四层:链路层、网络层、传输层、套接字层(应用层逻辑由用户进程实现,不属内核栈)。这不是教科书式的 OSI 七层映射,而是内核数据流穿行的真实路径。每层对应一组核心数据结构和处理函数,sk_buff 是贯穿全程的“数据包载体”,它不存数据本身,只通过指针管理缓冲区头尾,各层仅移动指针、增删头部,避免拷贝。

  • 链路层:处理 ethhdr、ARP 请求/响应,驱动收包后调用 netif_receive_skb() 入栈;发包前调用 dev_queue_xmit()
  • 网络层:核心是 ip_rcv()ip_forward(),查 FIB 路由表(ip route show 查看)、做分片/重组、校验 IP 头
  • 传输层:TCP 用 tcp_v4_rcv(),UDP 用 udp_rcv()端口查找靠 inet_hashinfo 结构,连接状态存在 struct sock
  • 套接字层:所有系统调用入口,如 bind()connect()sendmsg() 最终都落到 sock->ops->xxx 函数指针上

sk_buff 是什么?为什么改错指针位置就丢包

sk_buff 是 Linux 网络栈的“命脉”——它不是数据容器,而是一个带多组指针(head/data/tail/end)的元结构。数据真正存在 DMA 分配的内存页里,sk_buff 只负责告诉各层:“当前有效数据从哪开始、到哪结束”。一旦某层(比如 TCP)在封装时没调用 skb_push() 扩展 data 指针,或错误调用 skb_pull() 导致 data > tail,后续层读取时就会越界或读空,表现为静默丢包、tcpdump 能抓到入包但应用层收不到。

  • 典型坑:skb_reserve(skb, ETH_HLEN) 必须在驱动收包后立即调用,否则以太网头会覆盖 IP 头
  • 调试技巧:用 skb_dump() 或在 netdev_rx_handler_register() 回调里打印 skb->lenskb_headlen(skb) 判断数据是否被意外截断
  • 注意:NAPI 轮询中,一个 sk_buff 可能被多个 CPU 并发访问,不能裸改指针而不加锁或使用 per-CPU 变量

网卡驱动怎么把包交给协议栈?别只盯着 ifconfig

物理网卡收包不是靠 ifconfigip link 启动的,而是靠驱动注册中断处理函数(如 e1000_intr())或 NAPI poll 函数(如 e1000_clean())。当网卡 DMA 完成,触发硬中断 → 内核调度软中断 NET_RX_SOFTIRQ → 执行 net_rx_action() → 调用驱动的 poll 方法批量收包 → 对每个包调用 netif_receive_skb() 进入协议栈。这个链条一旦断裂(比如驱动未启用 NAPI、net.core.netdev_budget 设太小),就会看到 /proc/net/devRX 计数增长但 netstat -s | grep -i "packet receive" 不变——包卡在驱动队列没进栈。

rpcms轻量开源内容管理系统3.3.3
rpcms轻量开源内容管理系统3.3.3

RPCMS是一款基于PHP+MYSQL的轻量型内容管理/博客系统,支持PHP5.6版本以上,支持win/Linux系统。它自主研发的RP框架(OPP方式),采用MVC架构搭建的高效、稳定的内容管理系统。灵活小巧,但有着强大的扩展性、丰富的插件接口和大量的模板。统一采用模板标签,轻松上手,让开发更方便!智能缓存机制让网站运行方面大幅度提高。系统特点:源码简洁、体积轻巧、功能丰富、安全、灵活等特点,完

下载
  • 验证是否进栈:运行 cat /proc/interrupts | grep eth0 看中断是否上升;再执行 watch -n1 'cat /proc/net/snmp | grep -A1 Tcp' 观察 TcpInSegs 是否同步增加
  • 常见误操作:用 ethtool -K eth0 gso off 关闭 GSO 后,大包在传输层被分片,若 MTU 配置不当,可能触发链路层反复重传
  • 虚拟网卡(如 veth)无中断,走的是直接函数调用路径:dev_hard_start_xmit()dev->netdev_ops->ndo_start_xmit() → 直接送入对端 sk_buff 队列

为什么 socket() 创建的 fd 能跨层通信?关键在 struct sock

用户调用 socket(AF_INET, SOCK_STREAM, 0) 时,内核分配一个 struct socket(含文件描述符接口)并关联一个 struct sock(含协议控制块)。后者才是协议栈真正的“身份凭证”:TCP 层的 tcp_v4_rcv() 收到包后,用五元组(源IP/端口、目的IP/端口、协议)查哈希表,找到匹配的 struct sock,再把包塞进它的接收队列 sk->sk_receive_queue。应用层 recv() 实际就是从这个队列里取包。

  • 所以 bind() 的端口、listen() 的 backlog、setsockopt()TCP_NODELAY,全作用于 struct sock 字段,而非文件描述符本身
  • 陷阱:多个线程同时 recv() 同一个 TCP socket,不会竞争 sk_receive_queue —— 因为内核已用 sk_lock 保护,但若用 SO_REUSEPORT 创建多个 socket 绑定同一端口,每个 socket 有独立队列,负载不均时需用 reuseport + BPF 做分流
  • 查看真实状态:ss -i 显示每个 socket 的 rcv_ssthreshcwnd 等字段,比 netstat 更贴近内核视角
内核网络栈不是静态模型,而是一条高速流水线:sk_buff 是传送带,struct sock 是工位编号,驱动和协议函数是机械臂。任何一层指针偏移、队列溢出、哈希冲突或锁争用,都会让包在某个环节“掉下传送带”——而这种故障往往没有日志,只有 tcpdump/proc/net/snmp 的数字差值在默默提醒你。

相关专题

更多
treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

536

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

17

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

24

2026.01.06

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1072

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

128

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1003

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

13

2026.01.19

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.07.18

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

58

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.8万人学习

Git 教程
Git 教程

共21课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号