准备:
(一)MySQL连接方式 🔗
到MySQL5.7为止,总共有五种,分别是TCP/IP,TLS/SSL,Unix Sockets,Shared Memory,Named pipes,下面我们就来看看这五种的区别:
方式 | 默认开启 | 支持系统 | 只支持本机 | 如何开启 | 参数配置 |
---|---|---|---|---|---|
TCP/IP | 是 | 所有系统 | 否 | –skip-networking=yes/no. | –port–bind-address |
TLS/SSL | 是 | 所有系统(基于TCP/IP)之上 | 是 | –ssl=yes/no. | –ssl-* options |
Unix Sockets | 是 | 类Unix系统 | 是 | 设置–socket= |
–socket=socket path |
Shared Memory | 否 | Windows系统 | 否 | –shared-memory=on/off. | –shared-memory-base-name= |
Named pipes | 否 | Windows系统 | 否 | –enable-named-pipe=on/off. | –socket= |
(二)MySQL数据包格式 🔗
Server向Client发送的数据包有两个原则:
- 每个数据包大小不能超过2^24字节(16MB)。
- 每个数据包前都需要加上数据包信息,也就是包头,由
payload_length
和sequence_id
构成。
Server to Client数据包格式:
Type | Name | Description |
---|---|---|
int<3> | payload_length | 具体的包内容长度,即payload 长度 |
int<1> | sequence_id | 序列 ID 随每个数据包递增,并可能环绕。它从 0 开始,并在命令阶段中开始新命令时重置为 0。(Sequence ID) |
string | payload | 去除包头(payload_length+sequence_id)后的数据[len=payload_length] payload of the packet |
如上图红色区域蓝色为整个MySQL数据包,可以看到具体的十六进制的内容,以及它的ASCII码。
十六进制数据包:
4a0000000a352e372e3236002f000000740b50355a73387100fff7c00200ff81150000000000000000000072232a7e3709052f333f535a006d7973716c5f6e61746976655f70617373776f726400
拆分解析数据包:
整个MySQL Packet由包头+具体数据构成,采用的是小端存储形式。已知包头由payload_length
和sequence_id
构成,其中payload_length
占三个字节,sequence_id
是占用一个字节。所以整个包头占用四个字节,包头的十六进制数据4a000000
,转换为字节流[74 0 0 0]
。数据内容长度74,sequence_id为0。
拆分后三部分的内容构成如下:
payload_length=4a0000
sequence_id=00
payload=0a352e372e3236002f000000740b50355a73387100fff7c00200ff81150000000000000000000072232a7e3709052f333f535a006d7973716c5f6e61746976655f70617373776f726400
(三)MySQL连接交互过程 🔗
MySQL客户端与服务器的交互主要分为两个阶段:握手认证阶段和命令执行阶段。
握手认证阶段 握手认证阶段为客户端与服务器建立连接后进行,交互过程如下:
- 服务器 -> 客户端:握手初始化消息
- 客户端 -> 服务器:登陆认证消息
- 服务器 -> 客户端:认证结果消息
命令执行阶段 客户端认证成功后,会进入命令执行阶段,交互过程如下:
- 客户端 -> 服务器:执行命令消息
- 服务器 -> 客户端:命令执行结果
MySQL客户端与服务器的完整交互过程如下:
连接MySQL并发送一条SHOW VARIABLES LIKE 'lower_case_%
语句过程如下:
- 第一步MySQL客户端与MySQL服务端进行TCP三次握手,建立起稳定的连接。
- MySQL服务端向客户端发送
Server Greeting proto=10 version=5.7.26
的Handshake Packet。 - 客户端解析的Handshake包进行逻辑处理,
Login Request user=root
是客户端发送的Auth Packet。 - 服务端认证成功客户端的Auth Packet之后,返回一个OK Packet。
- 可以看到我们只发送了一次请求:
SHOW VARIABLES LIKE 'lower_case_%'
,但是客户端居然有两次Request Query,实际上第一次的Query是客户端发送SET NAMES utf8
的请求到服务端,指定了客户端和服务器之间传递字符的编码规则为UTF8。第二次的Request Query是我们发送的SQL语句。 - 服务端接受并解析了我们的请求,把结果放在Response Packet传回来。
(四)补充字节序 🔗
MySQL的数据传输基于小端存储形式。
- 大端序(Big-Endian)将数据的低位字节存放在内存的高位地址,高位字节存放在低位地址。这种排列方式与数据用字节表示时的书写顺序一致,符合人类的阅读习惯。
- 小端序(Little-Endian),将一个多位数的低位放在较小的地址处,高位放在较大的地址处,则称小端序。小端序与人类的阅读习惯相反,但更符合计算机读取内存的方式,因为CPU读取内存中的数据时,是从低地址向高地址方向进行读取的。