Skip to content

LV001-网络分层模型与TCP-IP协议栈 ​

一、 网络为什么要分层 ​

1. 一次性解决所有问题是不现实的 ​

两台设备要通信,要解决的问题有一大堆:

  • 物理层:用几伏电压表示 0 和 1,用几根线,双绞还是同轴;
  • 链路层:怎么把一串比特划成一段一段的帧,怎么知道帧的开头和结尾,出错了要不要重传;
  • 网络层:怎么在成百上千台设备里找到目标,怎么跨过一段又一段的链路;
  • 传输层:数据丢了好不好重传,谁先发谁后发,对方来不及收怎么办;
  • 应用层:对方拿到的字节流到底该怎么理解,是文件、是网页还是一句命令。

把这五类问题一次性全解决是不现实的:它们彼此的关注点完全不同,混在一起写,任何一处改动都会牵动全部。

工程上的做法是分层:每一层只解决一类问题,只跟自己的上下层打交道。

2. 分层带来的三个好处 ​

(1)换硬件不影响上层。这块板子用的是 DM9000 网卡,换一颗别的网卡芯片,TCP/IP 以上的部分一行都不用改。

(2)换应用不影响下层。今天跑 TFTP 拉固件,明天跑 HTTP 传网页,底下的 TCP/IP 与网卡驱动都不动。

(3)每层的责任清晰,出问题能按层排查。这也是后面查网络故障时"从物理往上逐层砍"这个思路的由来:先看网口灯,再看网卡 ID,再看地址,再看 ARP,最后才怀疑协议栈。

3. 分层的代价 ​

分层不是免费的,代价主要有两条:

  • 首部开销:每往下走一层就加一个头部。一个 ping 包真正想传的数据可能只有 8 字节,实际在网线上跑的却有 42 字节以上。
  • 层间复制与查表:每层的收发都要有自己的缓冲、查表与状态机,对内存只有 64 KB 的 STM32F103 来说,这些都是要精打细算的开支。

本工程的做法是"要分层,但每一层都裁到刚好够用"——这正是后面 LV015-lwIP配置与初始化 里那张 lwipopts.h 裁剪表的由来。

二、 两种分层模型 ​

1. OSI 七层与 TCP/IP 四层的对应 ​

教材里最常出现的是 OSI 七层模型,而实际互联网跑的是 TCP/IP 四层模型。两者的对应关系如下:

OSI 七层TCP/IP 四层这一层负责什么典型协议 / 设备
应用层、表示层、会话层应用层面向具体业务HTTP、DNS、TFTP、DHCP
传输层传输层进程到进程(靠端口区分)TCP、UDP
网络层网络层(网际层)主机到主机(跨网段寻址)IP、ICMP
数据链路层、物理层网络接口层一跳之内(同一条链路)以太网、MAC、PHY

如果按 OSI 的七层展开,从上到下依次是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

2. 为什么实际只谈四层 ​

OSI 的"表示层、会话层"在 TCP/IP 里被并进应用层了。原因是这两层在实际实现中很难划出清晰的边界:数据怎么编码(表示层)通常由具体应用自己决定,而"会话"的概念更多落在应用自己的状态机里。

所以实际写代码时基本只谈四层,本系列文档也统一按四层展开。

3. 一处归属争议:ARP 属于哪一层 ​

教材里对 ARP 的说法不统一:

  • 它报文的承载方式属于数据链路层——ARP 报文直接封在以太网帧里跑,帧类型字段是 0x0806;
  • 它干的事情却是为网络层服务——把 IP 地址解析成 MAC 地址。

所以更准确的理解是夹在网络层与网络接口层之间。本系列把它放在 LV030-ARP与MAC地址 单独讲,讲完再看归属问题会清楚得多。

三、 数据是怎么一层层封装起来的 ​

1. 发送加头、接收脱头 ​

发数据是从上往下逐层加头,收数据是从下往上逐层脱头:

text
发送方向 ↓                                   接收方向 ↑
应用层        应用数据                          应用数据
传输层        [TCP头][应用数据]                  脱 TCP 头
网络层        [IP头][TCP头][应用数据]            脱 IP 头
链路层        [以太网头][IP头][TCP头][数据][校验] 脱以太网头

每一次"加头"就是一次封装,每一次"脱头"就是一次解封装。

TCP/IP 分层与数据封装过程

帧里每一个字段具体占几个字节、校验覆盖哪一段,LV005-数据封装与以太网帧 会逐个字段拆开讲,这里先看整体形态。

2. 一次 ping 的报文拆解 ​

以一次 ping 为例,板子收到的报文会长这样:

部分长度内容
以太网头14 字节目的 MAC、源 MAC、类型(0x0800 表示里面装的是 IPv4)
IP 头20 字节版本、总长、源 IP、目的 IP、协议号(1 表示 ICMP)……
ICMP 报文8 字节起类型(8 = 请求,0 = 应答)、校验和、标识、序号、数据

3. 三种地址各自管多远 ​

链路层最大的一个特点:以太网头里的 MAC 地址只在一跳之内有效,每经过一台路由器就会被重写一次;而 IP 头里的地址是端到端的,一路不变。

把三种地址摆在一起看最清楚:

地址工作在哪一层作用范围
MAC 地址数据链路层一跳之内,换一个路由器就变了
IP 地址网络层端到端,全程不变
端口号传输层同一台主机上区分是哪个程序

一句话概括:MAC 找到"下一跳的那台设备",IP 找到"最终的那台设备",端口找到"那台设备上的哪个程序"。

跨网段时这两种地址的表现差异会成为一个关键结论,见 LV015-网关与跨网段通信 第三节。

四、 把分层映射到 lwIP 的源码目录 ​

1. 分层与文件的对照表 ​

本项目用的 lwIP 2.1.3(atk-f103/Components/lwip-2.1.3/)目录结构与四层模型几乎是直译的:

分层本工程中的文件说明
应用层port/iap_tcp.c、Drivers/BSP/Ota/ota_tftp.c自己写的 TCP 服务器与 TFTP 客户端
传输层src/core/tcp.c、tcp_in.c、tcp_out.c、udp.cTCP/UDP 的实现
网络层src/core/ipv4/ip4.c、ip4_addr.c、icmp.c、etharp.cIP 收发、地址处理、ICMP、ARP
网络接口层port/ethernetif.c + Drivers/BSP/Ethernet/dm9000.clwIP 与网卡的接口 + 网卡驱动本身
平台适配port/lwipopts.h、port/sys_arch.c、port/arch/cc.h不属于某一层,服务于整个协议栈

2. 后面几篇各讲哪个文件 ​

记住上面这张表,"读哪一篇对应哪个文件"就清楚了:

(1)地址与掩码(LV010-IP地址与子网掩码)→ ip4_addr.c。

(2)交换机、路由器与网关(LV020、LV015)→ 主要是硬件侧的事,协议栈里没有直接对应文件。

(3)ARP(LV030)→ etharp.c。

(4)传输层:端口、UDP 与 TCP(LV035)→ tcp.c、tcp_in.c、tcp_out.c、udp.c。

(5)DHCP(LV040)→ src/core/ipv4/dhcp.c,本工程把它裁掉了,只做源码对照。

(6)网络调试工具(LV045)→ 工具侧的事,与决策树搭配用。

(7)一次 ping 的全过程(LV050)→ 串起 icmp.c、ip4.c、etharp.c、ethernetif.c。

3. 两个术语的用法 ​

"TCP/IP"这个词有两种用法,读到时要看语境:

(1)狭义:指 TCP 和 IP 这两个协议本身。

(2)广义:指整套协议族(TCP/IP 协议栈),包含 IP、TCP、UDP、ICMP、ARP 等等。

lwIP 这个名字是 "lightweight IP" 的缩写,但它是一整套协议栈,不只是 IP 协议。

五、 小结与参考资料 ​

1. 本篇小结 ​

  • 网络分层是为了"每层只解决一类问题",也让排错可以按层逐段缩小范围;代价是首部开销与层间缓冲。
  • OSI 七层与实际用的 TCP/IP 四层可以对照,OSI 的上三层对应 TCP/IP 的应用层。
  • 发数据是逐层加头(封装),收数据是逐层脱头(解封装)。
  • 四层里每一层用不同的地址:MAC 管一跳、IP 管端到端、端口管进程。
  • 以太网帧类型字段是分流的依据:0x0806 → ARP,0x0800 → IPv4。
  • lwIP 的目录结构就是这套分层的直接映射,后面的文档都围绕这张表展开。

2. 参考资料 ​


本文档由 markdowncli 技能辅助生成