📚 第一章 网络基础知识
📄 一句话概括

一次网页打开,就是七层各干一次活、各加一个头。 中间设备只处理到自己那一层为止——这是分层最实际的价值。

📝 本节和前面几节的关系

1.5 讲清了分层是什么,1.6 用一次完整的通信把七层走一遍。 1.6.2 与 1.6.3 会分别放大上半段与下半段,这一节先看全景。

一、一次网页打开的全程

在浏览器里敲一个地址,七层各自做了什么:

层 动作 产物
应用层 生成 HTTP 请求 GET / HTTP/1.1
表示层 定编码、压缩 Accept-Encoding: gzip
会话层 管连接与身份 Cookie、keep-alive
传输层 分段、加端口 TCP 段,20 字节头
网络层 定路线、加 IP IP 包,20 字节头
链路层 找下一跳地址 以太网帧,14 字节头
物理层 变成信号 电/光

最上面三行在 TCP/IP 里是同一层干的: HTTP 一个协议就把「要什么」「能不能压缩」「带哪个 Cookie」全写进头部了。 所以真实抓包时看不到「表示层」和「会话层」的独立头部——它们变成了应用层头部里的几个字段。 第四行的分段是这一节的转折点:从这一层开始,数据要被「切」, 因为底下有长度上限(MTU)。 切法不同,就导向了 1.6.3 讲的两种命运(TCP 的 1460 与 UDP 的 1472)。

二、发送端加头,接收端剥头

两端是完全镜像的两套动作:

动作 发送端 接收端
顺序 从上往下加头 从下往上剥头
每层 在前面插入本层头 看本层头、再剥掉
检查 算校验和填进去 重算,不对就丢
最终 交给网卡发出去 交给应用程序

第三行那个「不对就丢」是很多诡异的根源:校验和错了,接收端不会通知你,直接丢掉。 发送端只知道「没收到确认」,不知道「为什么没收到」。 于是只能重传——这就是为什么网络问题常常表现为「慢」而不是「错」。 第四行那个「交给应用程序」是分层的终点:应用程序看到的永远是干净的原始数据, 所有头部都已经被剥掉,一个字节都没有多。 这也是为什么写应用的人可以不关心网络细节。

三、中间设备只到某一层

这是分层最实际的收益,也是最容易忽略的一点:

设备 处理到第几层 看不看得到内容
中继器、集线器 物理层 看不到,只放大信号
交换机 链路层 看 MAC,不看 IP
路由器 网络层 看 IP,不看端口
防火墙、代理 传输层以上 看得到端口与内容

这四行解释了一个常见困惑:为什么换一个交换机,IP 地址不用改? 因为它只处理到链路层,根本不知道 IP 的存在。 而换一个网段就必须改 IP,因为路由器是按 IP 转发的。 最后一行是「分层」被打破的地方: 防火墙要看端口号,就必须解析到传输层;要看内容(比如拦某个关键词),就得解析到应用层。 解析得越深,性能越差、也越容易被加密挡住——这就是为什么加密普及之后,深度检测越来越难做。

四、动手 Demo:七层通信,一层一层加头

从 27 字节的 HTTP 报文出发,一层一层加头,看累计长度。 这就是本节第一张表的代码版。

import _netsim as N

app = b'GET / HTTP/1.0\r\n\r\n'.ljust(27, b'x')
print('%-8s %-16s %-8s %s' % ('层', '动作', '本层头', '累计'))
print('-' * 48)
print('%-8s %-16s %-8s %d' % ('应用层', 'HTTP 报文', '—', len(app)))

seg = N.tcp4h(40000, 80, flags=0x18) + app
print('%-8s %-16s %-8s %d' % ('传输层', '加 TCP 头', N.TCP_HDR, len(seg)))

pkt = N.ip4h('192.168.3.152', '93.184.216.34', seg)
print('%-8s %-16s %-8s %d' % ('网络层', '加 IP 头', N.IP_HDR, len(pkt)))

frm = N.eth('00:11:22:33:44:55', '9c:b6:d0:0d:d5:0f', pkt)
print('%-8s %-16s %-8s %d' % ('链路层', '加以太网头', N.ETH_HDR, len(frm)))

print('物理层   发 %d 个比特' % (len(frm) * 8))

实跑输出:

--------------------------------------------------------------------
七层通信,一层一层加头
--------------------------------------------------------------------
**「7 层通信」在书上是张图;在代码里就是「把上一层的整包当成数据」。**

  层         动作             本层头     累计长度
  ------------------------------------------------
  应用层     HTTP 报文        —          27
  传输层     加 20 字节头     20         47
  网络层     加 20 字节头     20         67
  链路层     加 14 字节头     14         81

**这张表里头部是空字节**(全 0),
**因为这里只关心长度,不关心内容**——**真实头部每个字段都有含义,4.7 与 6.7 会逐个拆。**

**「7 层」在 TCP/IP 里只体现为 4 次加头**,**但书上的七层图仍然有用**:
**它把「编码」「会话」这两件事单独标出来了**,**提醒你这两件事不能忘——哪怕协议栈不替你管。**

27 → 47 → 67 → 81,四层一共加了 54 字节头:头比数据本身还多一倍。 这就是小请求在线上很「贵」的直接原因。 头部这里填的是空字节(全 0),只关心长度:真实头部每个字段都有含义, 第四章会拆 IP 头,第六章会拆 TCP 头。 「七层」在 TCP/IP 里只体现为四次加头:因为最上面三层被并成一层了。 但书上的七层图仍然有用:它把「编码」和「会话」这两件事单独标了出来, 提醒你这两件事不能忘——哪怕协议栈不替你管。

30 秒实验

  1. 把 app 改成 1400 字节,看链路层总长会不会超过 1514(以太网帧的实际上限)。
  2. 算一下:如果一次要传 10 KB 数据,TCP 至少要切成几个段?
  3. 想一下:为什么防火墙越「智能」越慢?用分层解释。

常见误区

  1. 以为七层在抓包里能看到七个头。 TCP/IP 里只有四个头,上面三层被并成了一层。
  2. 以为中间设备都懂全部七层。 交换机只到二层、路由器只到三层,正因为如此, 换交换机不用改 IP。
  3. 以为校验和出错会报错。 接收端直接丢包,不通知, 发送端只能靠超时重传——所以网络问题常表现为「慢」。
自测三问(点开对答案) 1. 一次网页打开,七层各自产生了什么? —— **应用层产生 HTTP 请求,传输层分段加端口,网络层定路线加 IP,链路层加 MAC 帧头,** **物理层变信号。** 上面三层的活都写进了 HTTP 头部。 2. 为什么换一个交换机不用改 IP,换一个网段就要改? —— **交换机只处理到链路层,看 MAC 不看 IP;路由器按 IP 转发**,网段变了 IP 就得跟着变。 3. 校验和错了为什么不直接报错给发送端? —— **因为接收端只是丢掉这个包**,没有回任何消息。发送端只能靠「没收到确认」推断,再重传。

下一节放大上半段:会话层以上到底在干什么。

相关笔记