通过Wireshark抓包分析TCP会话

前言

本文基于Wireshark抓包工具捕获的真实TCP会话数据,详细展示了客户端(100.80.77.84)与服务器(39.156.68.81,百度服务器)之间的TCP连接全过程。通过系统分析这些按时间顺序排列的数据包,我们可以清晰地了解TCP的三次握手、TLS握手、数据传输和连接维护的完整过程。

当然,你可以理解为这是计网的一次动手实践,我们的目标只是高屋建瓴地认识TCP会话的过程而已。细节部分会在之后的博客更新。

〇、简易抓包示例

在windows系统中使用Wireshark抓包无疑是最舒适的;如果是Linux系统的话还需要使用tcpdump,比较麻烦,感兴趣可以看这篇小林的文档:https://xiaolincoding.com/network/3_tcp/tcp_tcpdump.html#_4-3-tcp-%E5%AE%9E%E6%88%98%E6%8A%93%E5%8C%85%E5%88%86%E6%9E%90

首先我们要做的是要知道客户端和服务器的ip地址:

  • 打开cmd,使用ipconfig即可查看自己的ip:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\Users\zhuho>ipconfig

Windows IP 配置

......

无线局域网适配器 WLAN:

连接特定的 DNS 后缀 . . . . . . . : tongji.edu.cn
IPv6 地址 . . . . . . . . . . . . : 2001:da8:8002:6bd1:c247:e162:bc85:f373
临时 IPv6 地址. . . . . . . . . . : 2001:da8:8002:6bd1:f81e:f68b:f2ce:43e0
本地链接 IPv6 地址. . . . . . . . : fe80::38a7:fc59:80ba:96ab%11
IPv4 地址 . . . . . . . . . . . . : 100.80.77.84
子网掩码 . . . . . . . . . . . . : 255.254.0.0
默认网关. . . . . . . . . . . . . : fe80::9e54:c2ff:fe0d:5002%11
100.81.255.254
  • 使用ping命令即可查看
1
2
3
4
5
6
7
8
9
10
11
12
C:\Users\zhuho>ping baidu.com

正在 Ping baidu.com [39.156.66.10] 具有 32 字节的数据:
来自 39.156.66.10 的回复: 字节=32 时间=30ms TTL=47
来自 39.156.66.10 的回复: 字节=32 时间=30ms TTL=47
来自 39.156.66.10 的回复: 字节=32 时间=30ms TTL=47
来自 39.156.66.10 的回复: 字节=32 时间=30ms TTL=47

39.156.66.10 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 30ms,最长 = 30ms,平均 = 30ms

请注意:不要在输入网址时开头添加https://这样的协议名称!这是因为Ping使用ICMP协议工作在网络层,其目标是测试特定IP地址的可达性;具体方式是,在向指定的目标主机发送ICMP Echo的请求数据包并等待响应。ICMP协议工作在网络层(与IP协议同层——实际上ICMP是IP协议的一个组成部分,它依赖于IP协议来传送消息。),而HTTP协议在应用层。

Ping不关心目标主机上运行什么服务(HTTP、FTP、SMTP等),它只测试主机是否可达和响应ICMP请求,这是比应用层服务更基础的网络功能。所以,正确的用法应该是直接ping域名本身:ping baidu.com,而不是 ping https://baidu.com.

1
2
C:\Users\zhuho>ping https://baidu.com
Ping 请求找不到主机 https://baidu.com。请检查该名称,然后重试。

安装好wireshark之后,选择用管理员身份打开,点击WLAN就能查看数据包交流的痕迹啦:

Wireshark提供了编号、时间、源地址、目标地址、协议、包长度、网络包信息在内的数据包传输内容。在选择其中一个之后,下方还会显示协议栈各层的详细信息,用这里的例子,从上到下就是:数据帧、数据链路层、IP层、UDP层和DNS应用层。下方右侧就是该数据包完整的报文。

接下来,我们需要使用过滤器来对特定的IP之间的交互进行选择。选择和我们之前得到的有相同ip地址的数据包,在IP地址上选择作为过滤器应用:

第二个IP地址找到后也如此操作,选择“且选中”:

这里上方会显示类似如图所示的信息:

为了查看交互情况而不是单向传输情况,我们需要将.src与.dst修改为.addr。修改完成后,按下回车即可。

接下来,我们根据抓包结果来逐步分析。

一、TCP三次握手过程

TCP连接的建立需要经过三次握手(Three-way Handshake)过程。

从捕获的数据包中,我们可以清晰地看到这一过程:

序号 时间 源IP 目标IP 协议 标志 说明
3432 70.931320 100.80.77.84 39.156.68.81 TCP [SYN] 客户端发起连接请求
3489 70.961079 39.156.68.81 100.80.77.84 TCP [SYN, ACK] 服务器确认,并请求连接
3490 70.961200 100.80.77.84 39.156.68.81 TCP [ACK] 客户端确认连接
  1. 第一次握手(包3432):
    • 客户端向服务器发送SYN包
    • Seq=0,Win=65535,MSS=1460,WS=256
    • SYN标志位置为1
    • 客户端进入SYN-SENT状态
  2. 第二次握手(包3489):
    • 服务器收到SYN包后,回复SYN+ACK包
    • Seq=0,Ack=1,Win=8192,MSS=1452,WS=32
    • SYN和ACK标志位都置为1
    • 服务器进入SYN-RECEIVED状态
  3. 第三次握手(包3490):
    • 客户端收到SYN+ACK包后,回复ACK包
    • Seq=1,Ack=1,Win=65280,Len=0
    • ACK标志位置为1
    • 双方都进入ESTABLISHED状态,连接建立成功

二、数据传输过程

连接建立后,客户端与服务器之间开始数据传输。从捕获的数据包中,我们可以看到多种数据传输的典型特征:

1. HTTP请求/响应

紧接着三次握手完成后,客户端与服务器开始了HTTPS通信(通过TLSv1.2协议):

序号 时间 源IP 目标IP 协议 长度 信息
3491 70.961545 100.80.77.84 39.156.68.81 TCP 1506 [ACK] Seq=1 Ack=1 Win=65280 Len=1452 [TCP PDU reassembled in 3492]
3492 70.961545 100.80.77.84 39.156.68.81 TLSv1.2 432 Client Hello (SNI=connector.baidu.com)
3513 70.992140 39.156.68.81 100.80.77.84 TCP 56 [ACK] Seq=1 Ack=1453 Win=8192 Len=0
3514 70.992574 39.156.68.81 100.80.77.84 TCP 56 [ACK] Seq=1 Ack=1831 Win=8476 Len=0
3515 70.993034 39.156.68.81 100.80.77.84 TLSv1.2 212 Server Hello, Change Cipher Spec, Encrypted Handshake Message
3516 70.993261 100.80.77.84 39.156.68.81 TLSv1.2 105 Change Cipher Spec, Encrypted Handshake Message

这里可以清晰看到TLS握手的完整过程:

  1. 客户端发送Client Hello(指定SNI=connector.baidu.com)
  2. 服务器回应ACK确认收到
  3. 服务器发送Server Hello和加密参数
  4. 客户端回应Change Cipher Spec,完成密钥交换

此阶段完成后,双方将使用协商好的加密参数进行后续安全通信。

2. 数据包传输特征

在数据传输阶段,我们可以观察到TCP协议的几个关键特性:

  • 数据分段:大量的TCP报文显示了TCP如何将应用数据分段传输
  • 确认机制:每个数据包都有相应的ACK确认
  • 窗口大小调整:可以看到窗口大小(Win=)的变化,体现了TCP的流量控制
  • 序列号与确认号:体现了TCP的可靠传输机制

从抓包中可以清晰看到数据传输的过程,例如:

1
2
3
4
5
6
3517 70.993448    100.80.77.84    39.156.68.81    TCP    1506 58685 → 443 [ACK] Seq=1882 Ack=159 Win=65280 Len=1452 [TCP PDU reassembled in 3518]
3518 70.993448 100.80.77.84 39.156.68.81 TLSv1.2 348 Application Data

// 服务器回应确认
3563 71.024057 39.156.68.81 100.80.77.84 TCP 56 443 → 58685 [ACK] Seq=159 Ack=1882 Win=8476 Len=0
3564 71.024057 39.156.68.81 100.80.77.84 TCP 56 443 → 58685 [ACK] Seq=159 Ack=3334 Win=8768 Len=0

更有代表性的是从包3724到3735的连续传输,清晰展示了TCP的分段传输和PDU重组机制:

1
2
3
4
5
6
3724 71.545624    100.80.77.84    39.156.68.81    TCP    1506 58685 → 443 [ACK] Seq=3628 Ack=516 Win=64768 Len=1452 [TCP PDU reassembled in 3735]
3725 71.545624 100.80.77.84 39.156.68.81 TCP 1506 58685 → 443 [ACK] Seq=5080 Ack=516 Win=64768 Len=1452 [TCP PDU reassembled in 3735]
3726 71.545624 100.80.77.84 39.156.68.81 TCP 1506 58685 → 443 [ACK] Seq=6532 Ack=516 Win=64768 Len=1452 [TCP PDU reassembled in 3735]
...
3734 71.545624 100.80.77.84 39.156.68.81 TCP 1506 58685 → 443 [ACK] Seq=18148 Ack=516 Win=64768 Len=1452 [TCP PDU reassembled in 3735]
3735 71.545624 100.80.77.84 39.156.68.81 TLSv1.2 495 Application Data

这些包展示了一个大型PDU(协议数据单元)被分为多个TCP段传输,并最终在包3735中重组完成为应用层数据。序列号的连续增长(3628→5080→6532→…→18148)体现了数据的有序传输。

3. 服务器响应与状态维护

从数据包中可以观察到服务器如何处理和维护TCP连接状态

1
2
3
4
// 服务器对客户端数据的确认
3743 71.576388 39.156.68.81 100.80.77.84 TCP 56 443 → 58685 [ACK] Seq=516 Ack=6532 Win=96384 Len=0
3744 71.576940 39.156.68.81 100.80.77.84 TCP 56 443 → 58685 [ACK] Seq=516 Ack=9436 Win=102144 Len=0
3745 71.576940 39.156.68.81 100.80.77.84 TCP 56 443 → 58685 [ACK] Seq=516 Ack=13792 Win=110976 Len=0

这部分数据包显示了服务器如何对客户端发送的多个数据段进行确认,并且逐步增加接收窗口大小(Win值从96384增加到110976),表明服务器有足够的缓冲区接收更多数据。

某些包中还可以看到TCP的选择性确认(SACK)功能:

1
2
3746 71.576940    39.156.68.81    100.80.77.84    TCP    66 443 → 58685 [ACK] Seq=516 Ack=16696 Win=119680 Len=0 SLE=19680 SRE=20041
3747 71.576940 39.156.68.81 100.80.77.84 TCP 66 443 → 58685 [ACK] Seq=516 Ack=9436 Win=108032 Len=0 SLE=10888 SRE=13792

这里的SLE(Start of Left Edge)和SRE(Start of Right Edge)表示选择性确认的范围,允许接收方只确认已正确接收的数据段,提高重传效率。

此外,在完整的抓包中还观察到TCP的保活(Keep-Alive)机制,用于在空闲时保持连接活跃状态。

三、TCP四次挥手过程

这里在百度抓包的时候犯轴了,关闭百度的时候传的全是RTT异常终止的包,没一次成功挥手的。后来用静态网页做测试的时候发现,其实只要把整个浏览器进程结束掉就没问题了。这里用我的博客https://0krblog.yqbirdmp.com/做测试:

在此我们可以清晰地看到完整的TCP四次挥手(Four-way Handshake)过程:

序号 时间 源IP 目标IP 协议 标志 说明
5785 237.080675 76.76.21.123 100.80.77.84 TCP [ACK] 连接活跃状态
6020 252.294784 100.80.77.84 76.76.21.123 TCP [FIN, ACK] 客户端发起连接终止
6041 252.362367 76.76.21.123 100.80.77.84 TCP [FIN, ACK] 服务器确认并发起自身连接终止
6048 252.362657 100.80.77.84 76.76.21.123 TCP [ACK] 客户端确认服务器的终止请求
  1. 第一次挥手(包6020):
    • 客户端发送FIN+ACK包,表示不再发送数据
    • Seq=5143,Ack=5922,FIN和ACK标志位置为1
    • 客户端进入FIN-WAIT-1状态
  2. 第二次挥手(包6041):
    • 服务器回复FIN+ACK包,既确认了客户端的FIN,又表示自己也准备关闭
    • Seq=5922,Ack=5144,FIN和ACK标志位置为1
    • 服务器进入LAST-ACK状态,客户端收到后进入TIME-WAIT状态
  3. 第三次挥手
    • 实际上在这个捕获中,服务器合并了传统的第二次和第三次挥手(一个ACK和一个FIN)为一个FIN+ACK包
    • 这是TCP协议优化的常见做法,称为”合并FIN与ACK”
  4. 第四次挥手(包6048):
    • 客户端收到服务器的FIN+ACK后,回复最后一个ACK
    • Seq=5144,Ack=5923,只有ACK标志位置为1
    • 客户端进入TIME-WAIT状态,等待2MSL(最大报文生存时间)后关闭
    • 服务器收到ACK后立即关闭连接

这个抓包完美展示了实际网络中的TCP四次挥手过程,特别是捕捉到了优化后的”三次挥手”形式(因为服务器合并了ACK和FIN)。

标准四次挥手过程:

  1. 第一次挥手:

    • 主动关闭方发送FIN包
    • FIN标志位置为1
    • 主动方进入FIN-WAIT-1状态
  2. 第二次挥手:

    • 被动关闭方收到FIN包后,回复ACK包
    • ACK标志位置为1
    • 被动方进入CLOSE-WAIT状态,主动方进入FIN-WAIT-2状态
  3. 第三次挥手:

    • 被动关闭方发送FIN包
    • FIN标志位置为1
    • 被动方进入LAST-ACK状态
  4. 第四次挥手:

    • 主动关闭方收到FIN后,回复ACK包
    • ACK标志位置为1
    • 主动方进入TIME-WAIT状态,等待2MSL后关闭
    • 被动方收到ACK后立即关闭连接

四、TCP连接的重要特性分析

基于我们的抓包分析,我们可以总结出TCP连接的几个关键特性:

  1. 可靠性保证
  • 序列号和确认号:每个包都有明确的Seq和Ack值,如包3724有Seq=3628,Ack=516
  • 累积确认:服务器使用包3743、3744等进行连续确认
  • 分段与重组:大量的[TCP PDU reassembled]标记显示了TCP如何处理大数据
  • **选择性确认(SACK)**:如包3746中的SLE=19680、SRE=20041表示对特定范围数据的确认
  1. 流量控制
  • 窗口大小动态调整:Win值从初始的8192到后来的131328的变化
  • 接收窗口通告:服务器通过Win字段告知客户端它能接收多少数据
  • 零窗口处理:虽然在抓包中未看到,但TCP会处理接收方缓冲区满的情况
  1. 拥塞控制
  • 慢启动:可从初始数据传输量较小逐渐增大的过程推断
  • 拥塞避免:虽然直接看不到算法执行,但稳定传输阶段体现了此特性
  • MSS协商:握手时的MSS=1460和MSS=1452表明双方协商了最大段大小
  1. 全双工通信
  • 独立的数据流:客户端和服务器有各自的序列号空间
  • 同时传输:时间戳相近的包显示双方可以同时发送数据
  • 独立的流量控制:各自维护接收窗口

(你别说,ai总结的还是很到位的,所以这里贴上。)

好了,本篇就讲到这里,明天就正式开始TCP的博客更新!🎉🎉🎉🎉🎉🎉