2

TCP包的结构: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都将保留绝对值而不是相对值,易于清楚呈现出连接报文的详情;
  • 报文4seq 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):
经典图


JinhaoPlus
1.5k 声望92 粉丝

扎瓦程序员


引用和评论

0 条评论