📘 第一章 了解Web及网络基础
📄 一句话概括

IP 只做一件事:把包从源地址送到目的地址。 它不重传、不排序、不保证到达——这三件事全推给上面的 TCP。

📝 本节和前面几节的关系

上一节跟一个字节走完全程,这一节单独看网络层那一段。IP 的「不负责」正是 HTTP 需要 TCP 的原因。

一、IP 头里有什么、没有什么

20 字节固定头里,关键字段只有五组:版本、首部长度、总长度、TTL、协议号, 再加上源地址与目的地址各 4 字节。 没有序号、没有确认号、没有重传计时器。 因为 IP 是「尽力而为」(best effort):能送到就送,送不到就算了。 这套设计的好处是简单——路由器只需要查表转发,不需要为每条连接维护状态。 全世界的骨干网能跑这么快,一半功劳在这个「不管」上。

二、地址为什么必须分层

IP 地址由「网络部分 + 主机部分」组成,中间用掩码划开。 这不是为了好看,是为了路由表能压缩:路由器只需要记「10.0.0.0/8 走这个口」, 不用记一千万台主机。 Demo 里本机出口地址是 192.168.3.152,属于私网段。 私网地址不能直接在公网路由,出去要经过 NAT 换成公网地址。 NAT 让 IPv4 多活了二十年,代价是端到端被破坏——外面的机器没法主动连进来, 这也是 P2P 和实时通信要打洞的原因。

三、分片:MTU 是硬约束

每种链路都有自己的最大传输单元。以太网 1500,PPPoE 少 8 字节,某些隧道再少 20 到 60 字节。 超过就必须分片。 分片很贵:每片都要重复 20 字节 IP 头,而且丢任何一片整个包都要重传。 所以现代做法是尽量避免分片——TCP 用 MSS 协商,路径上再用 PMTUD 探测, 遇到「不分片」标志就回 ICMP 让你改小。 经典故障:中间设备把 ICMP 全拦了,PMTUD 探不出来,大包全丢、小包正常,登录取密码页能开、 提交就卡死。这叫 MTU 黑洞。

四、动手 Demo:本机出口地址、MTU 与 IP 头的开销

取本机在默认路由上的地址(不发包,只看内核选哪张网卡),判断是不是私网, 再算 IP 头在不同 MTU 下的占比。

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((u'8.8.8.8', 53))        # UDP connect 不发包
ip = s.getsockname()[0]
priv = ip.startswith(u'10.') or ip.startswith(u'192.168.')
for mtu in (1500, 9000):
    print(mtu, u'能装 TCP 数据', mtu - 20 - 20)

实跑输出:

--------------------------------------------------------------------
IP 只管把包送到,不管送到之后怎样
--------------------------------------------------------------------
  本机出口地址               192.168.3.152
  是否私网地址               是
  IP 头固定部分              20 字节(最长 60,选项最多 40)
  TTL 默认值                 通常是 64 或 128,每过一个路由器减一
  MTU 1500 能装的 TCP 数据   1460 字节
  MTU 9000 能装的 TCP 数据   8960 字节

  1 字节请求占 IP 净荷       20 + 20 + 1 = 41 字节
  IP 头占比                  48.8%
  IP 是「尽力而为」:它不重传、不排序、不保证到达,这三件事全部推给上面的 TCP。
  所以 IP 头里没有「序号」「确认号」——只有地址、长度、TTL 和校验和。

UDP connect 只设置目的地址、不产生任何报文,所以这一行既拿到了地址又没打搅网络。 MTU 1500 能装的 TCP 数据 1460、MTU 9000 能装的 TCP 数据 8960——两个数都是「减掉 40」, 这 40 字节在每一跳上都要重复占用带宽。 1 字节请求占 IP 净荷 41 字节、IP 头占比 48.8%——极端例子,但它说明短报文有多吃亏。

30 秒实验

  1. 把 8.8.8.8 换成 192.168.1.1,看出口地址变不变(大概率不变)。
  2. 算一算:MTU 1500 下,一个 4000 字节的 TCP 报文会被分成几片、每片多少字节。
  3. 查一下自己机器的网卡 MTU(netsh interface ipv4 show subinterfaces),看有没有不是 1500 的。

常见误区

  1. 「IP 保证送到」——只保证尽力,丢了不赔。
  2. 「IP 地址就是设备编号」——它是「网络位置」,换网络就得换地址。
  3. 「分片是路由器的事,客户端不用管」——分片会大幅降低效率,而且中间设备常常直接丢弃分片包。
自测三问(点开对答案) 1. IP 头里为什么没有重传相关字段? —— 因为它不做重传。可靠性由上层 TCP 自己实现。 2. 私网地址为什么不能直接上网? —— 公网路由器不为私网段维护路由,必须经 NAT 换成公网地址。 3. MTU 黑洞是怎么形成的? —— 路径上某段 MTU 更小,而 ICMP 又被拦截,PMTUD 探不到,导致大包全被丢弃。

IP 把包送到了,但送的过程可能乱序、可能丢。下一节看 TCP 怎么把这些补回来。

相关笔记