Appearance
题目
主机 H 通过快速以太网连接 Internet,IP 地址为 192.168.0.8,服务器 S 的 IP 地址为 211.68.71.80。H 与 S 使用 TCP 通信时,在 H 上捕获的其中 5 个 IP 分组如题 47-a 表所示。
题 47-a 表 5 个 IP 分组的前 40 字节内容(十六进制):

请回答下列问题。
(1) 题 47-a 表中的 IP 分组中,哪几个是由 H 发送的?哪几个完成了 TCP 连接建立过程?哪几个在通过快速以太网传输时进行了填充?
(2) 根据题 47-a 表中的 IP 分组,分析 S 已经收到的应用层数据字节数是多少?
(3) 若题 47-a 表中的某个 IP 分组在 S 发出时的前 40 字节如题 47-b 表所示,则该 IP 分组到达 H 时经过了多少个路由器?
题 47-b 表 来自 S 的某分组(前 40 B):

附 IP 头与 TCP 头结构:IP 头前 20 B 字段顺序为 版本(4b) + 头长(4b) + 服务类型(8b) + 总长度(16b) + 标识(16b) + 标志(3b) + 片偏移(13b) + TTL(8b) + 协议(8b) + 头部校验和(16b) + 源 IP(32b) + 目的 IP(32b)。
TCP 头前 20 B 字段顺序为 源端口(16b) + 目的端口(16b) + 序号(32b) + 确认号(32b) + 头长(4b) + 保留(6b) + 标志位 URG/ACK/PSH/RST/SYN/FIN(6b) + 窗口(16b) + 校验和(16b) + 紧急指针(16b)。
解析
如何在 hex dump 里找字段:以太网帧 14 B 头之后是 IP 数据报。IP 头前 20 B 占字节 0~19(dump 中表的字节 0~19 行),TCP 头紧跟其后 占字节 20~39。每个 IP 分组在表里只显示前 40 B,正好覆盖完整 IP 头 + TCP 头。
(1) 哪几个由 H 发送 / 完成 TCP 建连 / 触发以太网填充
判定 H 发送的分组:源 IP 在 IP 头字节偏移 12~15。H 的 IP = 192.168.0.8 = c0 a8 00 08(hex)。
| 分组 | 字节 12~15 | 源 IP | H 发送? |
|---|---|---|---|
| 1 | c0 a8 00 08 | 192.168.0.8 | ✓ |
| 2 | d3 44 47 50 | 211.68.71.80 | ✗(来自 S) |
| 3 | c0 a8 00 08 | 192.168.0.8 | ✓ |
| 4 | c0 a8 00 08 | 192.168.0.8 | ✓ |
| 5 | d3 44 47 50 | 211.68.71.80 | ✗(来自 S) |
→ H 发送的是 1、3、4 号分组。
判定哪几个完成 TCP 建连:检查 TCP 头标志位。TCP 头标志位在 IP 数据报字节 33(IP 头 20 B + TCP 头偏移 13 B = 33)的低 6 位。表中每个分组的字节 33 是 dump 第二行右数第二个字节。
更直接的方法是抓 SYN/ACK 标志组合:
| 分组 | TCP 标志位(看 SYN/ACK) | 说明 |
|---|---|---|
| 1 | 70 02 → 0x02 = SYN 单独置位 | 第 1 次握手(H → S:SYN) |
| 2 | 70 12 → 0x12 = SYN + ACK | 第 2 次握手(S → H:SYN+ACK) |
| 3 | 50 10 → 0x10 = 仅 ACK | 第 3 次握手(H → S:ACK) |
| 4 | 50 18 → 0x18 = ACK + PSH | 数据传输(H → S 发应用数据) |
| 5 | 50 10 → 0x10 = 仅 ACK | S 对 H 数据的确认 |
→ 1、2、3 号分组完成了 TCP 三次握手建连过程。
判定哪几个被以太网填充:
快速以太网(100BaseT)数据帧最小载荷 = 46 B(不含 14 B 帧头和 4 B FCS,即 IP 分组层面 ≥ 46 B)。
读 IP 总长字段(字节 2~3):
| 分组 | 字节 2~3 | 总长度 | < 46 B?需填充? |
|---|---|---|---|
| 1 | 00 30 | 48 | ✗ |
| 2 | 00 30 | 48 | ✗ |
| 3 | 00 28 | 40 | ✓ 填充 |
| 4 | 00 38 | 56 | ✗ |
| 5 | 00 28 | 40 | ✓ 填充 |
→ 3、5 号分组在以太网传输时被填充(在帧尾补 0 凑足 46 B)。
填充发生在哪一层:以太网(数据链路层)发现载荷 < 46 B 时自己加填充字节——这部分填充对网络层/传输层透明,IP 总长度字段不会因为填充而改变(IP 总长仍是真实数据长度)。接收方根据 IP 总长字段就能正确剥离填充。
(2) S 已收到的应用层数据字节数
核心思路:S 的"已收到字节数"= S 端的"下一个期望接收序号" − "数据起始序号"。
- 数据起始序号:3 号分组(第 3 次握手 ACK + 数据起始)的 TCP 序号(字节 24~27 处)=
84 6b 41 c6= 0x846B41C6 - S 当前期望序号:5 号分组(S 对 H 的 ACK)的 TCP 确认号(字节 28~31)=
84 6b 41 d6= 0x846B41D6
已收到字节数 = 0x846B41D6 − 0x846B41C6 = 0x10 = 16 字节。
为什么用 5 号分组的 ack:5 号分组是 S → H 的 ACK,它的"确认号"字段 = S 期望从 H 接收的下一个字节序号。差值 = S 已累计接收的应用数据。
(3) 47-b 中分组经过的路由器数
先确认 47-b 描述的是哪个分组:47-b 是从 S 端"出发时"的快照,47-a 是在 H 端"到达时"的快照——比较两者 IP 标识字段(字节 4~5)能找到对应:
| 分组 | 字节 4~5 | 标识 |
|---|---|---|
| 47-a 1 号 | 01 9b | 0x019B |
| 47-a 2 号 | 00 00 | 0 |
| 47-a 3 号 | 01 9c | 0x019C |
| 47-a 4 号 | 01 9d | 0x019D |
| 47-a 5 号 | 68 11 | 0x6811 |
| 47-b | 68 11 | 0x6811 |
→ 47-b 对应 47-a 中的 5 号分组。
比较 TTL(字节 8)的差:
- 47-b(S 出发):字节 8 =
40→ TTL = 0x40 = 64 - 47-a 5 号(H 到达):字节 8 =
31→ TTL = 0x31 = 49
经过的路由器数 = 64 − 49 = 15 个。
TTL 减 1 规则:每经过一个路由器 TTL 减 1。源主机出发时的 TTL 与目的主机收到时的 TTL 之差就是路径上的路由器跳数。
常见 TTL 初值速记:Linux/Unix → 64;Windows → 128;古早 BSD → 255。本题 47-b 的 0x40 = 64 暗示 S 是 Linux 服务器。