mysql协议解析源码_怒肝两个月MySQL源码,2W字MySQL协议详解(超硬核)

最近,在开发一个分库分表中间件,由于功能需求,需要分析MySQL协议,发现网上对于MySQL协议分析的文章大部分都过时了,原因是分析的MySQL版本太低了。怎么办呢?于是乎,我便硬着头皮开始啃MySQL源码,经过两个多月的整理,终于总结出这篇MySQL协议。

注:部分来自于互联网,感谢数据库大牛前辈们的默默付出!

交互过程

MySQL客户端与服务器的交互主要分为两个阶段:握手认证阶段和命令执行阶段。

握手认证阶段

握手认证阶段为客户端与服务器建立连接后进行,交互过程如下:

服务器 -> 客户端:握手初始化消息

客户端 -> 服务器:登陆认证消息

服务器 -> 客户端:认证结果消息

命令执行阶段

客户端认证成功后,会进入命令执行阶段,交互过程如下:

客户端 -> 服务器:执行命令消息

服务器 -> 客户端:命令执行结果

MySQL客户端与服务器的完整交互过程如下:

3e60d21122b0d71321ee0d52d1befccc.png

基本类型

整型值

MySQL报文中整型值分别有1、2、3、4、8字节长度,使用小字节序传输。

字符串(以NULL结尾)(Null-Terminated String)

字符串长度不固定,当遇到'NULL'(0x00)字符时结束。

二进制数据(长度编码)(Length Coded Binary)

数据长度不固定,长度值由数据前的1-9个字节决定,其中长度值所占的字节数不定,字节数由第1个字节决定,如下表:

aacdc469bb6f733c13eb9ef84930c126.png

字符串(长度编码)(Length Coded String)

字符串长度不固定,无'NULL'(0x00)结束符,编码方式与上面的 Length Coded Binary 相同。

报文结构

报文分为消息头和消息体两部分,其中消息头占用固定的4个字节,消息体长度由消息头中的长度字段决定,报文结构如下:

047a0d126cf8154552a6522989681758.png

消息头

报文长度

用于标记当前请求消息的实际数据长度值,以字节为单位,占用3个字节,最大值为 0xFFFFFF,即接近 16 MB 大小(比16MB少1个字节)。

序号

在一次完整的请求/响应交互过程中,用于保证消息顺序的正确,每次客户端发起请求时,序号值都会从0开始计算。

消息体

消息体用于存放请求的内容及相应的数据,长度由消息头中的长度值决定。

报文类型

登陆认证交互报文

握手初始化报文(服务器 -> 客户端)

fc80ef64b815e0e6206076fb8962bb8f.png

服务协议版本号:该值由 PROTOCOL_VERSION 宏定义决定(参考MySQL源代码/include/mysql_version.h头文件定义)

服务版本信息:该值为字符串,由 MYSQL_SERVER_VERSION 宏定义决定(参考MySQL源代码/include/mysql_version.h头文件定义)

服务器线程ID:服务器为当前连接所创建的线程ID。

挑战随机数:MySQL数据库用户认证采用的是挑战/应答的方式,服务器生成该挑战数并发送给客户端,由客户端进行处理并返回相应结果,然后服务器检查是否与预期的结果相同,从而完成用户认证的过程。

服务器功能标志:用于与客户端协商通讯方式,各标志位含义如下(参考MySQL源代码/include/mysql_com.h中的宏定义):

6043df9d4ea77ddb7648b17a32c56843.png

字符编码:标示服务器所使用的字符集。

服务器状态:状态值定义如下(参考MySQL源代码/include/mysql_com.h中的宏定义):

fcab4ec47e8104b2ce276daac6b06d26.png

登陆认证报文(客户端 -> 服务器)

MySQL 4.0 及之前的版本

876cd4dc81628d1be43e0e9e3cc741a3.png

MySQL 4.1 及之后的版本

38e31702e1d12f2472c316d0b940e417.png

客户端权能标志:用于与客户端协商通讯方式,标志位含义与握手初始化报文中的相同。客户端收到服务器发来的初始化报文后,会对服务器发送的权能标志进行修改,保留自身所支持的功能,然后将权能标返回给服务器,从而保证服务器与客户端通讯的兼容性。

最大消息长度:客户端发送请求报文时所支持的最大消息长度值。

字符编码:标识通讯过程中使用的字符编码,与服务器在认证初始化报文中发送的相同。

用户名:客户端登陆用户的用户名称。

挑战认证数据:客户端用户密码使用服务器发送的挑战随机数进行加密后,生成挑战认证数据,然后返回给服务器,用于对用户身份的认证。

数据库名称:当客户端的权能标志为 CLIENT_CONNECT_WITH_DB 被置位时,该字段必须出现。

客户端命令请求报文(客户端 -> 服务器)

4ee5d336f0d1ed13fdcac3dae22d0378.png

命令:用于标识当前请求消息的类型,例如切换数据库(0x02)、查询命令(0x03)等。命令值的取值范围及说明如下表(参考MySQL源代码/include/mysql_com.h头文件中的定义):

98c99e810f7de1e95cb4a79a907c02fc.png

参数:内容是用户在MySQL客户端输入的命令(不包括每行命令结尾的";"分号)。另外这个字段的字符串不是以NULL字符结尾,而是通过消息头中的长度值计算而来。

例如:当我们在MySQL客户端中执行use hutaow;命令时(切换到hutaow数据库),发送的请求报文数据会是下面的样子:

0x02 0x68 0x75 0x74 0x61 0x6f 0x77

其中,0x02为请求类型值COM_INIT_DB,后面的0x68 0x75 0x74 0x61 0x6f 0x77为ASCII字符hutaow。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值