目录
TCP的报头格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
各字段的原文说明
Sequence Number: 32 bits
The sequence number of the first data octet in this segment (except
when SYN is present). If SYN is present the sequence number is the
initial sequence number (ISN) and the first data octet is ISN+1.
Acknowledgment Number: 32 bits
If the ACK control bit is set this field contains the value of the
next sequence number the sender of the segment is expecting to
receive. Once a connection is established this is always sent.
Data Offset: 4 bits
The number of 32 bit words in the TCP Header. This indicates where
the data begins. The TCP header (even one including options) is an
integral number of 32 bits long.
Reserved: 6 bits
Reserved for future use. Must be zero.
Control Bits: 6 bits (from left to right):
URG: Urgent Pointer field significant
ACK: Acknowledgment field significant
PSH: Push Function
RST: Reset the connection
SYN: Synchronize sequence numbers
FIN: No more data from sender
Window: 16 bits
The number of data octets beginning with the one indicated in the
acknowledgment field which the sender of this segment is willing to
accept.
Checksum: 16 bits
The checksum field is the 16 bit one's complement of the one's
complement sum of all 16 bit words in the header and text. If a
segment contains an odd number of header and text octets to be
checksummed, the last octet is padded on the right with zeros to
form a 16 bit word for checksum purposes. The pad is not
transmitted as part of the segment. While computing the checksum,
the checksum field itself is replaced with zeros.
The checksum also covers a 96 bit pseudo header conceptually
三次握手的过程
Linux 上抓包直输出在屏幕上展示三次握手
[root@zyq tmp]# tcpdump -i virbr1 host bb and tcp port 80
15:38:02.917805 IP phy.50430 > bb.http: Flags [S], seq 255094098, win 29200, options [mss 1460,sackOK,TS val 24762854 ecr 0,nop,wscale 7], length 0
源端发起请求,然后处于 SYN-SENT 状态,SYN=1 seq=255094098。
15:38:02.917948 IP bb.http > phy.50430: Flags [S.], seq 3366673141, ack 255094099, win 28960, options [mss 1460,sackOK,TS val 23898905 ecr 24762854,nop,wscale 7], length 0
服务端收到请求,SYN=1 ACK=1 seq=3366673141,ack=255094099(请求的 seq + 1),然后处于 SYN-RCVD 状态。
15:38:02.917968 IP phy.50430 > bb.http: Flags [.], ack 1, win 229, options [nop,nop,TS val 24762854 ecr 23898905], length 0
源端收到报文并发给服务端 ACK=1 ,然后处于 ESTABLISHED 状态,服务端收到报文后也处于 ESTABLISHED 状态,TCP 连接的建立。
Linux 上抓包保存,通过 WireShark 查看
1 0.000000 192.168.2.254 192.168.2.12 TCP 74 50432 → 80 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=25013122 TSecr=0 WS=128
源端发起请求,然后处于 SYN-SENT 状态,SYN=1 seq=0。
2 0.000158 192.168.2.12 192.168.2.254 TCP 74 80 → 50432 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=24149173 TSecr=25013122 WS=128
服务端收到请求,SYN=1 ACK=1 seq=0,ack=1(请求的 seq + 1),然后处于 SYN-RCVD 状态。
3 0.000177 192.168.2.254 192.168.2.12 TCP 66 50432 → 80 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=25013122 TSecr=24149173
源端收到报文并发给服务端 ACK=1 ,seq=1(发起请求时候的 seq + 1),ack=1(收到服务端的 seq + 1),然后处于 ESTABLISHED 状态,服务端收到报文后也处于 ESTABLISHED 状态,TCP 连接的建立。
tcpdump VS WireShark
tcpdump 直接输出到屏幕,只能展示大概的信息,并不全面,WireSharK 展示的信息更详细一些,在进行抓包排查的时候,初步分析可以直接 tcpdump 打印到屏幕上,但要进行更详细细的分析需借助 WireShark。
四次挥手过程
通过 WireShark 展示四次断开
1 0.000724 192.168.2.254 192.168.2.12 TCP 66 50432 → 80 [FIN, ACK] Seq=67 Ack=247 Win=30336 Len=0 TSval=25013123 TSecr=24149173
发起关闭连接 FIN=1 ACK=1(确认收到了服务端发来的一个包并期望收到下一个包),seq=67,ack=247,这个时候为 FIN_WAIT_1 状态,如果收到后续传来的包,会继续给服务端响应收到了包,并等待关闭连接 。
2 0.000812 192.168.2.12 192.168.2.254 TCP 66 80 → 50432 [FIN, ACK] Seq=247 Ack=68 Win=29056 Len=0 TSval=24149173 TSecr=25013123
收到客户端断开连接的请求并通知给 web 程序,等待 web 程序关闭此连接同时给客户端发送确认断开连接, FIN = 1 ,ACK = 1 ,ack=68(最后一个断开连接的 seq + 1 ),seq=247,这时候服务端处于 CLOSE_WAIT 状态。
3 0.000827 192.168.2.254 192.168.2.12 TCP 66 50432 → 80 [ACK] Seq=68 Ack=248 Win=30336 Len=0 TSval=25013123 TSecr=24149173
确认收到服务端发来的断开连接请求,并继续等待两个 2MSL 的时间。客户端直到2MSL 后都没有收到服务端发送过来的包,才断开连接,服务端在收到自己断开连接请求的确认包后,就直接进入断开连接状态。
Linux 直接打印到屏幕四次断开
15:38:02.918524 IP phy.50430 > bb.http: Flags [F.], seq 67, ack 247, win 237, options [nop,nop,TS val 24762855 ecr 23898906], length 0
15:38:02.918656 IP bb.http > phy.50430: Flags [F.], seq 247, ack 68, win 227, options [nop,nop,TS val 23898906 ecr 24762855], length 0
15:38:02.918669 IP phy.50430 > bb.http: Flags [.], ack 248, win 237, options [nop,nop,TS val 24762855 ecr 23898906], length 0
为什么客户端最后还要等待 2MSL?
MSL(Maximum Segment Lifetime)
一、确保客户端发送的最后一个确认报文能到达服务器,客户端发送的最后一个确认报文可能丢失,如果服务器没有收到客户端发送来的确认报文,会重新发起一个断开连接的确认报文,客户端在这个时间如果再次收到服务端发来的断开连接的报文,就会重新发起一个确认断开的报文并刷新 2MSL 计时器。
二、让本次连接传送的报文全部从网络上消失,理论上这个时间可以实现这个目的。
参考