共计 3490 个字符,预计需要花费 9 分钟才能阅读完成。
TCP 包的结构:TCP 协议规定的数据报文的构造
TCP 报文中的序列号 seq 和确认号到底指什么?
序列号 seq(sequence numer)
序列号 seq,其实 TCP 发送 payload 数据的每一个字节都是有编号的,每个报文的编号其实就是 这个报文 payload 数据中的首个字节的编号 ,通俗的例子:
一共发了 3 个报文:P1(payload=aaa), P2(payload=bb), P3(payload=c),那么
P1.seq=0
P2.seq=3(P1.seq+p1.payload.length)
P3.seq=5(P2.seq+p2.payload.length)
确认号 ack(acknowledge numer)
确认号 ack,其实是对前一个对端发送来的报文的回复,ack=x+ 1 说明之前对端发送来的 x 个字节的 payload 数据都已经收到了,请对端下次发送 seq=x+ 1 的报文吧,或者说叫 期望从对端收到的下一字节的序号。通俗的例子:
A 主机发来了 P1(payload=aaa), B 主机接收到 P1 报文后需要发回确认报文 R1:
P1.seq=0
R1.ack=3(P1.seq+p1.payload.length)
tcpdump 抓包分析
抓在 80 端口上的 TCP 包:
> tcpdump -S 'tcp and port 80'
21:33:01.704998 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [S], seq 396038856, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 744881175 ecr 0,sackOK,eol], length 0
其中传输的 Flags 释义:
- [S]:SYN,表示开始连接
- [.]:没有标记,一般是确认
- [P]:PSH,表示数据推送
- [F]:FIN,表示结束连接
- [R]:RST,表示重启连接
抓包的一组 TCP 连接传输断开的数据报文:
> tcpdump -S 'tcp and port 80'
21:33:01.704998 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [S], seq 396038856, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 744881175 ecr 0,sackOK,eol], length 0
21:33:01.717502 IP 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http > 192.168.31.72.61146: Flags [S.], seq 2345237966, ack 396038857, win 14400, options [mss 1412,nop,nop,sackOK,nop,wscale 7], length 0
21:33:01.717542 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [.], ack 2345237967, win 4096, length 0
21:33:01.718011 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [P.], seq 396038857:396039622, ack 2345237967, win 4096, length 765: HTTP: POST /mmtls/22207be4 HTTP/1.1
21:33:01.727958 IP 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http > 192.168.31.72.61146: Flags [.], ack 396039622, win 125, length 0
21:33:01.758550 IP 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http > 192.168.31.72.61146: Flags [P.], seq 2345237967:2345238289, ack 396039622, win 125, length 322: HTTP: HTTP/1.1 200 OK
21:33:01.758735 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [.], ack 2345238289, win 4090, length 0
21:33:01.759551 IP 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http > 192.168.31.72.61146: Flags [F.], seq 2345238289, ack 396039622, win 125, length 0
21:33:01.759693 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [.], ack 2345238290, win 4090, length 0
21:33:01.773281 IP 192.168.31.72.61146 > 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http: Flags [F.], seq 396039622, ack 2345238290, win 4096, length 0
21:33:01.786917 IP 101.165.151.61.dial.xw.sh.dynamic.163data.com.cn.http > 192.168.31.72.61146: Flags [.], ack 396039623, win 0, length 0
梳理一下:
报文传输方向 | Flags | seq | ack | payload length |
---|---|---|---|---|
C -> S | [S] | 396038856 | 0 | |
S -> C | [S.] | 2345237966 | 396038857 | 0 |
C -> S | [.] | (396038857) | 2345237967 | 0 |
C -> S | [P.] | 396038857(:396039622) | 2345237967 | 765 |
S -> C | [.] | (2345237967) | 396039622 | 0 |
S -> C | [P.] | 2345237967(:2345238289) | 396039622 | 322 |
C -> S | [.] | (396039622) | 2345238289 | 0 |
S -> C | [F.] | 2345238289 | 396039622 | 0 |
C -> S | [.] | (396039622) | 2345238290 | 0 |
C -> S | [F.] | 396039622 | 2345238290 | 0 |
S -> C | [.] | (2345238290) | 396039623 | 0 |
下面图示了整个连接、传输和断开过程的 TCP 数据报:
其中需要注意的点有:
- 为了避免过长的 seq 和 ack,图中 seq 和 ack 只展示了后 3 位;
- tcpdump 开启 - S 命令后,所有的 seq 和 ack 都将保留绝对值而不是相对值,易于清楚呈现出连接报文的详情;
- 报文 4
seq 396038857:396039622 length 765
,这个意思是 seq=396038857,其报文的 payload length=765,所以对端 ack 的时候应该 ack=396039622(即表示 396039622 前的字节我都收到了,下一次请给我编号为 396039622 及以后的字节),显示这个就不需要人读的时候再手工计算了,简单明了的展示清楚,不过第一次用的话会很懵。报文 5ack 396039622
印证了这个观点; - 为什么 syn 报文明明 payload length=0,对端 ack 还要加 1 呢?因为 syn 是建立连接的关键报文,而为了确保对方接收到,使用超时重传机制,TCP 规定,只为有数据的 TCP 报文重传,SYN 占据一个序号(可以认为只有一个字节数据的报文,即使其 payload length=0),这样做 TCP 也会重传 SYN 报文;
- ack 的 payload length=0,可以看到 ack 报文发送后之后的报文 seq 并没有变;
可以对照此经典图进行分析(不过要注意这个图里数据传输过程中的数据报文假定 payload length=1):
正文完