1. 网络协议栈概述:从物理信号到应用数据

大家好,我是你们的讲师。今天咱们聊聊网络协议栈的总体框架。说实话,我做了十几年内核网络开发,每次带新人时,第一件事就是让他们把这张「地图」刻在脑子里。没有全局观,你调起 bug 来会非常痛苦。

1.1 OSI七层模型 vs TCP/IP四层模型

先看这张经典的对比图。很多教科书喜欢把 OSI 七层模型捧得很高,但实际干活的人都知道——TCP/IP 四层模型才是真家伙。OSI 更多是理论参考,TCP/IP 是实战标准。

OSI 七层模型 TCP/IP 四层模型 核心作用
应用层 应用层 HTTP、FTP、DNS 等协议
表示层 数据加密、压缩、格式转换
会话层 建立/管理/终止会话
传输层 传输层 TCP/UDP,端口到端口的通信
网络层 网络层 IP 路由、寻址、分片
数据链路层 网络接口层 MAC 地址、帧封装、差错检测
物理层 比特流传输、电气信号

我个人习惯把 OSI 当作「面试题」,把 TCP/IP 当作「吃饭工具」。你想想看,Linux 内核里哪有表示层和会话层的影子?它们被合并到应用层里了。说白了,OSI 是理想,TCP/IP 是现实。

核心要点:TCP/IP 四层模型是 Linux 内核网络协议栈的实现基础。每一层只关心自己的事,下层为上层服务。这种分层设计让内核代码变得非常优雅——当然,也带来了不少性能开销。

1.2 Linux网络协议栈架构总览

好,咱们把目光聚焦到 Linux 内核。下面这张图是我手绘的协议栈架构,你仔细看——数据从网卡进来,一路向上,经过层层处理,最后到达应用层。反过来也一样。

Linux 网络协议栈数据流架构 应用层 (Application Layer) Socket API · 系统调用 · 用户态进程 传输层 (Transport Layer) TCP · UDP · 端口管理 · 拥塞控制 网络层 (Network Layer) IPv4/IPv6 · 路由查找 · 分片重组 · Netfilter 数据链路层 (Data Link Layer) 以太网 · MAC 地址 · 网卡驱动 · 桥接 物理层 (Physical Layer) 网线 · 光纤 · 无线信号 数据接收方向 数据发送方向 socket tcp_v4_rcv ip_rcv netif_receive_skb

嗯,这里要注意——每一层之间的「接口」是固定的。传输层和网络层之间通过 struct sk_buff 传递数据,这个结构体是整个协议栈的「血液」。我在项目中遇到过不少性能问题,最后追根溯源,都是 sk_buff 的分配和拷贝太频繁了。

避坑指南:我曾经在调优一个网关设备时,发现吞吐量上不去。查了三天,最后发现是 sk_buff 的共享内存池配置太小,导致频繁的 kmalloc。把内存池调大后,性能直接翻倍。所以,sk_buff 的管理是协议栈优化的第一课

1.3 数据包在内核中的旅程

咱们来走一遍数据包的完整旅程。从网卡收到一个比特流开始,到应用层读到数据,中间经历了什么?我习惯把这个过程分成 6 个关键步骤:

  1. 网卡接收:物理信号变成数字帧,DMA 写入内存
  2. 驱动层处理:NAPI 轮询,构造 sk_buff,调用 netif_receive_skb()
  3. 数据链路层:检查 MAC 地址,剥掉以太网头,交给 ip_rcv()
  4. 网络层处理:IP 校验、路由查找、分片重组,交给 tcp_v4_rcv()
  5. 传输层处理:TCP 状态机、序列号检查、流量控制,放入 socket 接收队列
  6. 应用层读取:通过系统调用 recvfrom()read() 从 socket 缓冲区拷贝到用户空间

你想想看,一个简单的 HTTP 请求,在内核里要经过这么多道工序。每一道工序都可能成为瓶颈。我记得有一次排查一个视频流卡顿的问题,发现是网络层的路由缓存过期策略太激进,导致每个包都要查路由表——这就是典型的「配置不当引发的性能灾难」。

关键数据结构:整个旅程中,struct sk_buff 是贯穿始终的「快递包裹」。它包含了数据指针、协议头偏移、时间戳、设备信息等。你可以把它理解成一个带目录的集装箱——每一层只操作自己关心的那部分。

1.4 为什么理解这个架构很重要?

说白了,你以后调网络性能、写内核模块、甚至排查应用层超时问题,都得靠这张「地图」来定位。比如:

  • 应用层超时,可能是传输层的重传超时设置不对
  • 吞吐量上不去,可能是网络层的路由缓存满了
  • 延迟忽高忽低,可能是数据链路层的 NAPI 轮询参数没调好

没有全局观,你就像在黑屋子里找开关——只能瞎摸。有了这张图,你至少知道「我现在在第几层,该往哪个方向查」。

注意:不要试图一次性搞懂所有细节。协议栈的代码量超过 50 万行,你不可能全记住。我的建议是:先搭框架,再填细节。遇到问题时,先定位到层,再深入具体函数。

好,这一章就到这里。记住这张架构图,后面的每一章都会围绕它展开。咱们下一章见。


专注资料整理