4. 观察TCP序号与确认号的变化规律

任务目标

使用Wireshark抓取一次TCP连续数据传输过程,跟踪报文段中序号(Seq)与确认号(Ack)的递增关系,验证TCP可靠传输中序号机制的工作方式。

环境准备

  • 安装Wireshark(版本≥3.0)
  • 本机回环接口(lo/Loopback)即可完成,无需额外网络设备
  • Python 3(用于生成可控的连续TCP数据流)

抓包与数据生成

为便于观察序号递增规律,使用Python在本地建立TCP客户端与服务器,传输一段已知长度的数据(例如20000字节)。回环接口抓包可避免网络噪声干扰,且序号变化清晰可追踪。

服务端脚本(server.py):

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 9999))
s.listen(1)
conn, addr = s.accept()
total = 0
while True:
    data = conn.recv(4096)
    if not data:
        break
    total += len(data)
conn.close()
s.close()
print(f"received {total} bytes")

客户端脚本(client.py):

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 9999))
payload = b'x' * 20000
s.sendall(payload)
s.close()

抓包步骤

  1. 启动Wireshark,选择回环接口(Loopback: lo),开始抓包。
  2. 先运行python server.py,再运行python client.py。
  3. 传输完成后停止抓包,在过滤栏输入tcp.port == 9999过滤出本次连接的所有报文。

序号与确认号分析

在Wireshark中依次点击每个TCP报文,观察Sequence Number与Acknowledgment Number字段。以下为关键观察点:

  • 三次握手阶段:SYN报文消耗一个序号,SYN-ACK的确认号=客户端初始序号+1。
  • 数据发送阶段:每个数据报文的Seq等于上一个数据报文的Seq + 上一个报文携带的字节数(Len列)。
  • ACK确认:接收方返回的Ack等于期望收到的下一个字节序号,即最后收到的Seq + Len。
  • 连续传输:若发送窗口足够,发送方无需等待每个ACK即可连续发送多个报文段,但每个报文的Seq仍严格按字节偏移递增。

以下为20000字节数据在回环接口传输时,抓包中前几个数据报文段的预期序号变化(MSS=16384,回环接口单段可承载全部数据):

# 方向: 客户端 → 服务器
报文1: Seq=1, Len=16384, Ack=1
报文2: Seq=16385, Len=3616, Ack=1
# 方向: 服务器 → 客户端(ACK确认)
报文3: Seq=1, Ack=20001, Len=0

其中Ack=20001表示服务器已正确收到序号1~20000的全部字节,期望下一个字节序号为20001。若数据被拆分为多个TCP段(如MSS较小),则每个段的Seq依次为1, 1+MSS, 1+2*MSS, ...,ACK始终指向最后收到的Seq+Len。

验证方法

  1. 在Wireshark中启用Sequence number列显示(默认已显示)。
  2. 选中任意数据报文,查看其Seq值,再选中下一个数据报文,确认其Seq = 前一个Seq + 前一个Len。
  3. 找到接收方返回的纯ACK报文(Len=0),确认其Ack = 最后一个收到的数据报文Seq + Len。
  4. 若传输过程中无重传,所有数据报文的Seq应严格单调递增,且相邻差值等于前序报文的Len字段。

通过条件:上述序号与确认号的数值关系在抓包中完全吻合,且最终ACK的确认号等于20001(即初始序号1 + 20000字节),说明序号机制按预期工作。

常见问题

  • 看到Seq不是从1开始:Wireshark默认显示相对序号(Relative Sequence Number),即减去初始ISN后的值。如需查看原始序号,右键点击列头选择Protocol Preferences → TCP → 取消勾选Relative Sequence Numbers。
  • 出现Seq跳变:若抓包中看到Seq不连续,可能是存在重传或乱序,此时应检查是否有TCP Retransmission标记。
  • 回环接口数据量小:若一次sendall被内核拆分为多个TCP段,只需按上述规则逐段验证即可,不影响结论。
时间 客户端 (发送方) 服务器 (接收方) 报文① 数据 Seq=1, Len=16384 报文② 数据 Seq=16385, Len=3616 报文③ ACK Ack=20001, Len=0 Seq = 1 Seq = 16385 Ack = 20001 关键规律: 报文②的Seq = 报文①的Seq + 报文①的Len = 1 + 16384 = 16385 ACK的Ack = 最后收到的Seq + Len = 16385 + 3616 = 20001

上图展示了本次抓包中三个关键报文的序号流动方向。实际抓包中报文数量可能更多(取决于MSS与窗口大小),但序号与确认号的递增规则完全一致:每个数据报文的Seq等于已发送字节总数+1,每个ACK的Ack等于已接收字节总数+1。