我目前正在使用 Google 的 packetdrill制作用于对 FreeBSD 的 TCP/IP 堆栈进行回归测试的测试脚本。但是,我遇到了一个涉及序列号的小问题。这是来自其中一个测试脚本的一小部分,用于验证 Early Retransmit 是否正常工作 -
// Three way handshake
0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
0.100 > S. 0:0(0) ack 1 <...>
0.200 < . 1:1(0) ack 1 win 257
0.200 accept(3, ..., ...) = 4
// Our application writes 2920 bytes
0.200 write(4, ..., 2920) = 2920
0.200 > P. 1:2921(2920) ack 1
0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop>
0.325 > . 1:1461(1460) ack 1 // delayed Early Retransmit at RTT/4 = 25ms
0.425 < . 1:1(0) ack 2921 win 257
0.500 close(4) = 0
0.500 > F. 2921:2921(0) ack 1
0.600 < F. 1:1(0) ack 2922 win 257
0.601 > . 2922:2922(0) ack 2
虽然测试很容易理解,但我想不通的是,为什么我们在PUSH的同时又发送了一个确认号1,因为在三向握手中,对方已经发送了一个ACK开始序列号为 1。这不应该是正确的行吗?
0.200 > P. 1:2921(2920) ack 2
0.300 < . 2:2(0) ack 1 win 257 <sack 1461:2921,nop,nop>
也可以看出,在0.425秒时,对方再次发送了一个相同序列号1:1的ACK。
完整的测试脚本可以在这里找到。
我本可以在 packetdrill 的邮件列表中发布这个问题,但我认为这是我的基础问题。
供快速参考~
- 起始小数表示以秒为单位的绝对计时。
<和>表示数据包的方向,<用于接收和>注入。- S表示SYN
- P表示PUSH
- F表示FIN
- . 表示ACK
- sack表示选择性确认。
accept(),close()和write()是适当的系统调用。