213 lines
10 KiB
Markdown
213 lines
10 KiB
Markdown
---
|
||
tags: [计算机网络, OSI模型, TCP/IP, 网络分层]
|
||
create time: 2026-05-17 22:10
|
||
---
|
||
|
||
# OSI 七层 vs TCP/IP 四层模型
|
||
|
||
## 概述
|
||
|
||
OSI(Open Systems Interconnection)和 TCP/IP 是理解计算机网络的两种经典分层模型。OSI 提供了一套理论化的参考框架,而 TCP/IP 则是实际运行在因特网上的协议栈。理解两者的映射关系,有助于我们在设计系统和排查问题时建立正确的抽象层次。
|
||
|
||
> [!QUESTION] 为什么现实用五层模型而不是 OSI?
|
||
> OSI 的七层理论很完美,但实现起来复杂到几乎不可能。TCP/IP 只有四层,又太粗。于是教学上采用折中的「五层模型」:把 OSI 的应用/表示/会话三层合并为应用层,保留传输层、网络层、链路层、物理层——刚好够表达所有关键概念。
|
||
|
||
## OSI 七层模型
|
||
|
||
### 分层结构
|
||
|
||
| 层级 | 名称 | PDU(协议数据单元) | 核心职责 |
|
||
|------|------|-----|---------|
|
||
| 7 | 应用层 | 数据(Data) | 为用户提供网络服务接口(HTTP、FTP、SMTP) |
|
||
| 6 | 表示层 | 数据 | 数据格式转换、加密解密、压缩解压 |
|
||
| 5 | 会话层 | 数据 | 建立/维护/终止会话(会话令牌、检查点) |
|
||
| 4 | 传输层 | 段(Segment) | 端到端可靠传输、流量控制、差错控制 |
|
||
| 3 | 网络层 | 包(Packet) | 路由选择、逻辑寻址(IP 地址) |
|
||
| 2 | 数据链路层 | 帧(Frame) | 物理寻址(MAC)、相邻节点间的帧传输 |
|
||
| 1 | 物理层 | 比特(Bit) | 电气特性、机械接口、光电信号转换 |
|
||
|
||
```mermaid
|
||
graph BT
|
||
subgraph "传输中封装"
|
||
D["应用层 Data"] --> L6["表示层: 加密+压缩"]
|
||
L6 --> L5["会话层: 建立/维护/结束会话"]
|
||
L5 --> S["传输层 Segment"]
|
||
S --> P["网络层 Packet"]
|
||
P --> F["链路层 Frame"]
|
||
F --> B["物理层 Bitstream"]
|
||
end
|
||
|
||
style D fill:#DDA0DD
|
||
style S fill:#FFD700
|
||
style F fill:#98FB98
|
||
style B fill:#B0C4DE
|
||
```
|
||
|
||
### 每层经典协议对照表
|
||
|
||
| 层 | 协议 | 作用场景 |
|
||
|----|------|---------|
|
||
| 应用层 | HTTP, DNS, SMTP, FTP, SSH, WebSocket | 应用间通信 |
|
||
| 表示层 | TLS/SSL, JPEG, MPEG, ASN.1 | 数据格式化与加密 |
|
||
| 会话层 | NetBIOS, RTP, SIP | 多路复用与同步 |
|
||
| 传输层 | TCP, UDP, SCTP | 端到端数据传输 |
|
||
| 网络层 | IP, ICMP, IGMP, ARP* | 跨网段路由转发 |
|
||
| 链路层 | Ethernet, Wi-Fi (802.11), VLAN, PPP | 相邻设备帧传输 |
|
||
| 物理层 | USB, RS-232, 光纤, Cat6 网线 | 物理信号传输 |
|
||
|
||
> [!note] ARP 到底在第几层?
|
||
> ARP 将 IP 地址解析为 MAC 地址,跨越了网络层和链路层的边界。OSI 将其放在**网络层下方、链路层上方**的"夹层"位置。现代观点常把它视为网络层的一部分。
|
||
|
||
## TCP/IP 四层模型
|
||
|
||
### 分层结构
|
||
|
||
| 层级 | 对应 OSI | 核心协议 | 核心职责 |
|
||
|------|----------|---------|---------|
|
||
| 应用层 | 7+6+5 层合并 | HTTP, DNS, SMTP, SSH | 面向应用的协议栈 |
|
||
| 传输层 | 4 层 | TCP, UDP | 端到端连接管理 |
|
||
| 网络层 | 3 层 | IP, ICMP, ARP | 分组路由与寻址 |
|
||
| 网络接口层 | 2+1 层合并 | Ethernet, Wi-Fi | 帧传输与物理介质 |
|
||
|
||
### 为何 OSI 没赢下标准之战
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A["OSI 七层模型<br/>ISO 标准"] --> B{谁先落地?}
|
||
B -->|"1983 Flag Day"| C["TCP/IP 正式接管 ARPANET"]
|
||
B -->|"标准滞后"| D["OSI 标准太多太复杂"]
|
||
C --> E["事实标准 ✅"]
|
||
D --> E
|
||
style E fill:#98FB98,color:#000
|
||
```
|
||
|
||
- **先发优势**:1983 年 1 月 1 日(Flag Day),ARPANET 强制切换到 TCP/IP,基础设施已建成,生态不可逆转
|
||
- **简单粗暴**:TCP/IP 只关心能不能跑通,不搞复杂的标准化流程
|
||
- **开源免费**:Berkeley BSD Unix 内嵌 TCP/IP 协议栈(1983 年 4.2BSD),免费分发
|
||
- **OSI 的反面教材**:层层审批导致协议膨胀(X.400 邮件、X.25 分组交换),开发者根本懒得用
|
||
|
||
## 五层教学模型
|
||
|
||
这是教材中最常用的模型,取两者精华:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A["应用层 — Application<br/>HTTP, DNS, SMTP, SSH, FTP, POP3, IMAP, WebSocket"] --> T["传输层 — Transport<br/>TCP, UDP, SCTP"]
|
||
T --> N["网络层 — Internet<br/>IP, IPv6, ICMP, ARP, NAT"]
|
||
N --> D["链路层 — Link<br/>Ethernet, Wi-Fi, 802.11, VLAN, HDLC, PPP"]
|
||
D --> P["物理层 — Physical<br/>双绞线, 光纤, 无线电, IEEE 802.15"]
|
||
style A fill:#DDA0DD
|
||
style T fill:#FFD700
|
||
style N fill:#87CEEB
|
||
style D fill:#98FB98
|
||
style P fill:#B0C4DE
|
||
```
|
||
|
||
> [!QUESTION] 为什么是五层,不是三层或八层?
|
||
> 分层的本质是**职责分离**——每一层只关心自己该做的事,通过标准接口向上层提供服务。层数太少(如三层)会导致单层职责过重,排查问题困难;层数太多则引入不必要的抽象开销。五层是一个兼顾教学清晰度和工程实用性的"甜蜜点"。
|
||
|
||
### 三层模型横向对比
|
||
|
||
下面的表格将三种模型放在同一张表里,方便你快速查清某一层在不同模型中的对应关系:
|
||
|
||
| 功能域 | OSI 层 | 五层模型 | TCP/IP 层 | 典型协议/技术 | 封装单元 |
|
||
|--------|--------|----------|-----------|---------------|----------|
|
||
| 应用逻辑 | 7 应用层 | 应用层 | 应用层 | HTTP, DNS, SMTP, SSH | Data |
|
||
| 数据表示 | 6 表示层 | ↗ | ↗ | TLS/SSL, JPEG, ASN.1 | Data |
|
||
| 会话管理 | 5 会话层 | ↗ | ↗ | NetBIOS, RTP, SIP | Data |
|
||
| 端到端传输 | 4 传输层 | 传输层 | 传输层 | TCP, UDP, SCTP | Segment |
|
||
| 路由寻址 | 3 网络层 | 网络层 | 网络层 | IP, ICMP, ARP | Packet |
|
||
| 帧传输 | 2 数据链路层 | 链路层 | 网络接口层 | Ethernet, Wi-Fi, PPP | Frame |
|
||
| 物理信号 | 1 物理层 | ↗ | ↗ | 光纤, 双绞线, 无线电 | Bit |
|
||
|
||
> [!tip] ↗ 符号的含义
|
||
> 上表中 ↗ 表示"向上合并"——五层模型把 OSI 的表示层、会话层并入应用层;TCP/IP 模型进一步把数据链路层、物理层合并为网络接口层。**合并不等于消除**,这些功能仍然存在,只是不再单独成层。
|
||
|
||
## 数据包逐层穿越过程
|
||
|
||
以你发送一封电子邮件为例:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant App as 你的邮件客户端
|
||
participant T as TCP层
|
||
participant I as IP层
|
||
participant L as 以太网层
|
||
participant Router as 路由器
|
||
participant R as 接收方
|
||
|
||
App->>T: SMTP 邮件内容 (Data)
|
||
T->>T: 加 TCP 首部 (Header + Data → Segment)
|
||
T->>I: 传递 Segment
|
||
I->>I: 加 IP 首部 (Header + Segment → Packet)
|
||
I->>L: 传递 Packet
|
||
L->>L: 加以太网帧头帧尾 (Header + Packet + FCS → Frame)
|
||
L->>Router: 通过网线发送 Frame
|
||
Router->>Router: 拆帧 → 查路由表 → 重新封帧
|
||
Router->>R: 转发给接收方
|
||
R->>L: 解包 → IP层校验 → TCP重组 → 提取 SMTP
|
||
R->>App: 邮件到达收件箱
|
||
```
|
||
|
||
> [!tip] 封装 = 套娃;解封装 = 剥壳
|
||
> 每一层只知道自己那一层的 header 是什么格式,对其他层的内容一无所知。这就是**层间透明**原则。
|
||
|
||
> [!QUESTION] 如果每一层都要加头部,开销岂不是很大?
|
||
> 没错。一个 1 字节的应用层数据,经过 TCP/IP/以太网三层封装后,可能膨胀到 58 字节(TCP 头 20B + IP 头 20B + 以太网帧头帧尾 18B)。这就是为什么对小数据量、低延迟场景,业界会选择 **UDP**(头部仅 8 字节)甚至 **QUIC**(合并传输层与加密层)来减少开销。
|
||
|
||
### MTU 与 MSS:分层边界如何约束数据大小
|
||
|
||
分层不只是理论模型,它直接决定了每层能传多大的数据:
|
||
|
||
| 概念 | 所在层 | 含义 | 典型值 |
|
||
|------|--------|------|--------|
|
||
| **MTU**(Maximum Transmission Unit) | 链路层 | 一个帧能承载的最大数据量 | 以太网默认 **1500B** |
|
||
| **MSS**(Maximum Segment Size) | 传输层 | 一个 TCP 段能承载的最大应用数据 | 1500 - 20(IP) - 20(TCP) = **1460B** |
|
||
|
||
> [!QUESTION] 为什么下载大文件时网络层会有大量小包?
|
||
> 当你要发一个 100KB 的文件时,TCP 会按 MSS(1460B)将其切割成约 70 个段,每个段再交给网络层封装成 Packet,最后由链路层加上帧头帧尾变成 Frame。**分层的每一级都有自己的大小限制**,超出就要分片或分段——这就是 Path MTU Discovery(路径 MTU 发现)存在的原因:找到整条路径上最小的 MTU,避免中间路由器做 IP 分片(分片会严重影响性能)。
|
||
|
||
## 分层在代码中的体现
|
||
|
||
理解分层模型,不只是为了面试,它直接影响你在编程中需要关心什么、不需要关心什么:
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"net"
|
||
)
|
||
|
||
func main() {
|
||
// 传输层:你只需告诉 OS "用 TCP 连这个地址"
|
||
// IP 路由、以太网帧封装、物理信号 —— 全部由内核和网卡处理
|
||
conn, err := net.Dial("tcp", "example.com:80")
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
defer conn.Close()
|
||
|
||
// 应用层:你手动构造 HTTP 请求(Data 层的内容)
|
||
request := "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
|
||
conn.Write([]byte(request))
|
||
|
||
// 读取应用层响应 —— 下面的 Segment/Packet/Frame 已被内核剥壳
|
||
buf := make([]byte, 4096)
|
||
n, _ := conn.Read(buf)
|
||
fmt.Println(string(buf[:n]))
|
||
}
|
||
```
|
||
|
||
这段代码里,程序员只和**应用层**(HTTP 报文)与**传输层**(`Dial("tcp", ...)`)打交道。网络层以下的路由、帧封装、电信号转换完全由操作系统和硬件代劳——这就是分层带来的**抽象红利**。
|
||
|
||
> [!QUESTION] 如果没有分层会怎样?
|
||
> 想象一下:每次发 HTTP 请求,你都要手动计算 IP 校验和、填写 MAC 地址、调制电信号……代码量和出错率会指数级上升。分层让我们可以**只关注自己那一层**,其余的交给下层实现。
|
||
|
||
## 关联笔记
|
||
|
||
- [[hhs/NETWORK/02-以太网帧结构]] — 链路层帧的详细结构
|
||
- [[hhs/NETWORK/03-IPv4协议详解]] — 网络层 IP 数据包格式
|
||
- [[hhs/NETWORK/04-TCP状态机详解]] — 传输层 TCP 连接管理
|
||
- [[hhs/NETWORK/05-HTTP请求响应]] — 应用层协议细节
|