MySQL 客户端与服务器之间通信的基本单位:数据包(Packets)
-
核心概念:分包传输
- 当客户端或服务器需要发送数据时,如果数据量很大,它不会一次性发送完。
- 它会将数据 拆分成较小的块,每个块就是一个
Packet。 - 每个 Packet 的最大有效载荷(Payload)是 16,777,215 字节(即 2²⁴ - 1 字节,或大约 16MB)。
-
Packet 结构
每个 Packet 由两部分组成:-
Packet Header (包头部 - 4 字节):
- **
payload_length(3 字节): 指定紧随其后的 Payload 部分的实际长度(单位:字节)。这 3 个字节是 小端字节序**。 - **
sequence_id(1 字节): 序列号**。用于标识数据包的顺序,防止乱序或丢失。发送方每发送一个 Packet,这个 ID 就递增一次(从 0 开始)。在每个新的命令开始时(命令阶段),序列号会重置为 0。这个 ID 允许回绕(超过 255 后又从 0 开始)。
- **
-
Payload (有效载荷 - 长度由
payload_length指定): 实际要传输的数据内容。这部分的结构取决于具体的命令或响应(例如 SQL 查询、查询结果、错误信息、认证信息等)。
-
-
发送超过 16MB 的数据
-
如果数据总长度正好等于或超过 16,777,215 字节,发送方需要拆分成多个 Packet。
-
第一个 Packet:
payload_length设置为0xFFFFFF(即 16,777,215 的十六进制表示,对应 3 个字节的FF FF FF)。- 只包含数据的前 16,777,215 字节作为 Payload。
-
后续 Packet(s):
- 发送剩余的数据。
- 每个后续 Packet 的
payload_length是其实际 Payload 的长度(小于或等于 16,777,215 字节)。 sequence_id会依次递增。
-
最后一个 Packet:
- 其
payload_length小于 16,777,215 字节(即不是FF FF FF),表示这是最后一个分块。
- 其
-
-
例子说明
文档给出了发送 16,777,215 字节 数据的极端例子:-
Packet 1:
FF FF FF 00+ (16,777,215 字节的 Payload)FF FF FF=payload_length= 16,777,21500=sequence_id= 0
-
紧接着发送 1 字节:
-
Packet 2:
01 00 00 01+ (1 字节的 Payload)01 00 00=payload_length= 1 (小端字节序:低位在前,实际值是00 00 01= 1)01=sequence_id= 1 (在上一个包的 0 基础上递增)
-
-
文档结构说明
- 文档描述了如何在文档中表示数据包:主要定义其 Payload 的结构(类型、字段含义)。
- 提供示例时会包含完整的 Packet(包括 Header)。
- 强调某些字段或整个包的结构可能依赖于连接时协商的 能力标志位 (Capability Flags)(例如是否启用 SSL、压缩、协议版本等)。
- 固定值通常用方括号
[ ]内的十六进制表示(例如[00])。
总结:
数据包是理解 MySQL 底层通信协议的基石。它定义了:
- 数据如何在网络上传输: 被打包成最大 16MB 的块。
- 包的结构: 4 字节头(长度 + 序列号) + 实际数据。
- 处理大数据的方法: 分包发送,用满 3 字节长度的
FF FF FF表示后面还有更多数据块。 - 保证顺序的机制: 递增的序列号 (
sequence_id)。
理解 MySQL Packets 对于进行网络抓包分析、开发 MySQL 客户端/服务器、理解高级特性(如压缩、SSL)如何在此基础协议上运作至关重要。文档中提到的函数(如 my_net_write, net_send_ok)是 MySQL 服务器/客户端内部实现这些协议逻辑的关键部分。