1. 网络基础回顾:从分层模型到Linux协议栈
做网络协议栈开发这些年,我见过不少同事一上来就扎进代码,结果被各种术语绕晕。其实,理解网络通信,关键就两件事:分层和封装。今天咱们先把地基打牢。
1.1 OSI七层模型 vs TCP/IP四层模型
你肯定听过OSI七层模型。理论上是完美的,但现实中没人完全照着它实现。为什么?太复杂了。七层划分过于细致,商用成本高。真正统治互联网的是TCP/IP四层模型。
我习惯把两者放在一起对比,这样能看清TCP/IP做了哪些“裁剪”。
| OSI七层模型 | TCP/IP四层模型 | 核心职责 | 典型协议/设备 |
|---|---|---|---|
| 应用层 | 应用层 | 为用户提供网络服务接口 | HTTP, FTP, DNS, SSH |
| 表示层 | 数据格式转换、加密、压缩 | SSL/TLS, JPEG, ASCII | |
| 会话层 | 建立、管理、终止会话 | NetBIOS, RPC | |
| 传输层 | 传输层 | 端到端可靠传输、流量控制 | TCP, UDP |
| 网络层 | 网络层 | 路由选择、逻辑寻址 | IP, ICMP, ARP |
| 数据链路层 | 网络接口层 | 帧封装、介质访问控制、差错检测 | 以太网, MAC地址, VLAN |
| 物理层 | 比特流传输、电气特性 | 网线, 光纤, 集线器 |
核心观点:TCP/IP模型把OSI上三层合并为应用层,把下两层合并为网络接口层。这种“务实”的设计,让协议栈实现更轻量,也更容易在操作系统内核中落地。
1.2 数据封装与解封装:数据包的“俄罗斯套娃”
网络通信的本质,就是数据在每一层被“套上”一个头部,然后在接收端一层层“拆开”。这个过程,我称之为“俄罗斯套娃”。
举个例子,你在浏览器里输入一个URL,按下回车。数据从应用层一路向下,每经过一层,都会加上该层的头部信息。
发送端:封装过程
- 应用层:生成HTTP请求报文(比如GET /index.html)。
- 传输层:加上TCP头部(源端口、目的端口、序列号等),形成TCP段。
- 网络层:加上IP头部(源IP、目的IP、TTL等),形成IP数据报。
- 网络接口层:加上以太网帧头部(源MAC、目的MAC、类型),尾部加上FCS校验,形成以太网帧。
接收端:解封装过程
- 网络接口层:检查MAC地址,校验FCS,去掉帧头部和尾部,交给网络层。
- 网络层:检查IP地址,去掉IP头部,交给传输层。
- 传输层:检查端口号,去掉TCP头部,重组数据,交给应用层。
- 应用层:解析HTTP报文,交给浏览器渲染。
避坑指南:我曾经在调试一个网络性能问题时,发现数据包总是丢。查了半天,结果是网卡驱动在解封装时,FCS校验没通过就直接丢弃了。所以,数据链路层的校验不是摆设,很多“玄学”问题都出在这一层。
1.3 Linux网络协议栈概览:内核里的“高速公路”
好了,理论讲完,咱们看看Linux内核里到底是怎么实现这套模型的。Linux网络协议栈,说白了就是内核里一套处理网络数据包的软件系统。它不是一个单一的模块,而是一系列模块的集合。
我个人习惯把协议栈分成三个层次来看:
- 套接字层(Socket Layer):给用户空间的应用程序提供系统调用接口(如socket, bind, send, recv)。它是用户态和内核态的“桥梁”。
- 传输层协议模块:实现TCP、UDP等协议。这是协议栈最复杂的部分,涉及拥塞控制、重传、滑动窗口等。
- 网络层与网络接口层:实现IP、ICMP、ARP,以及和网卡驱动交互的部分。数据包在这里被路由、转发、最终发送到物理介质。
你想想看,一个数据包从应用程序发出,到网线,中间要经过多少函数调用?几十个。每个函数都可能成为性能瓶颈。
注意:Linux协议栈是软中断驱动的。网卡收到数据后,通过硬中断通知CPU,CPU在软中断上下文里处理数据包。如果软中断处理时间过长,会导致网络延迟飙升。这是调优的关键点。
1.4 知识体系总览:一张图看懂协议栈
下面这张图,是我画给团队新人的。它把上面讲的所有内容串在了一起。你盯着看三分钟,就能建立起全局观。
1.5 为什么要在内核里实现协议栈?
你可能想问:为什么不在用户态实现?嗯,这个问题我当年也纠结过。后来在项目中踩了坑才明白:
- 性能:内核态可以直接操作硬件(网卡),避免频繁的用户态/内核态切换。每次切换都有开销,高并发场景下不可接受。
- 安全性:协议栈是共享资源,多个进程同时使用。内核统一管理,防止进程间互相干扰或恶意篡改数据。
- 统一性:所有网络应用都通过相同的系统调用接口访问协议栈,行为可预测,调试更方便。
个人经验:我曾经参与过一个DPDK项目,把协议栈搬到用户态。性能确实提升了30%,但代价是应用逻辑变得极其复杂,而且失去了内核的安全隔离。所以,除非你有极致的性能需求,否则别轻易动内核协议栈。
1.6 本章小结
这一章,我们干了三件事:
- 对比了OSI和TCP/IP模型,明白了TCP/IP为什么是“务实”的选择。
- 拆解了数据封装和解封装过程,理解了数据包在每一层的“变身”。
- 鸟瞰了Linux网络协议栈的整体架构,知道了它和理论模型的对应关系。