博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

MySQL源码分析之 通信协议(一)

Posted on 2022-05-13 12:23  面具下的戏命师  阅读(1768)  评论(0编辑  收藏  举报

MySQL源码分析之 通信协议(一)

mysql 通信协议用于 mysql 客户端和服务器之间的通讯,通过以下几种方式实现:

 1)、接口: (Connector/C, Connector/J, 等) 即平时我们所说的 JDBC ODBC 等接口

 2)、mysql 中间件

 3)、主服务器和从服务器之间的通信

mysql 协议支持一下几点功能:

 1)、使用 SSL 的透明加密

 2)、透明压缩

 3)、连接阶段,进行身份验证和数据交换的能力

 4)、执行阶段,接收客户端发来的命令并执行他们

交互过程:

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

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

  • 服务器 -> 客户端:握手初始化消息
  • 客户端 -> 服务器:登陆认证消息
  • 服务器 -> 客户端:认证结果消息

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

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

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

 

基本类型:

1、整型

整型分为固定长度的整型和可变长度的整型(变长在这里指的是存储长度)。

固定长度类型属于无符号整型,分别有1、2、3、4、6、8字节长度,使用小字节序传输最低有效字节排在第一位。以3字节长度整型为例可以查看 int3store()

变长整型,可能占用1、3、4、9个字节,具体取决于其数值。把一个整型值转换为一个可变字节长度存储需要如下操作:

因此,如果需要将变长存储的整型转化为数值,需要检查第一个字节。

注意: 如果数据包的第一个字节是长度编码的整数,其字节值为0xFE,则必须检查数据包的长度,以验证其是否有足够的空间容纳8字节整数。如果不是,它可能是一个EOF数据包。 

2、字符串

字符串在协议中有以下几种形势:

1)、固定长度的字符串,具有已知的硬编码长度。例如,ERR数据包的sql状态总是5字节长

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

3)、字符串的长度由另一个字段确定,或在运行时计算

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

5)、如果字符串是数据包的最后一个组成部分,则可以从数据包的总长度减去当前位置来计算其长度。

报文结构:
如果 MySQL 客户端和服务器想发送数据,需要将数据拆为2**24大小的数据包(即16M)因此客户端和服务器之间以最大16M 的数据包进行交换。会为每个数据块预先添加一个数据包头。因此可以这么理解:报文分为消息头和消息体两部分,其中消息头占用固定的4个字节,消息体长度由消息头中的长度字段决定,报文结构如下:

  

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

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

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

通用响应包(服务响应报文):

响应包可以分为三种,OK_Packet、 ERR_Packet、EOF_Packet。从MySQL 5.7.5开始,OK数据包也被用来表示EOF,EOF数据包被弃用。如果设置了CLIENT_PROTOCOL_41,即MySQL 版本大于4.1。 

该数据包包含一个警告计数。

1、OK 响应报文

客户端的命令执行正确时,服务器会返回OK响应报文。

如果 header = 0 并且packer 长度大于7,说明这个包是 OK 数据包

如果 header = 0xFE 并且 packer 长度小于9,说明这个包是 EOF 包。 

affecred rows:受影响行数,当执行 INSERT/UPDATE/DELETE 语句时所影响的数据行数

last_insert_id: 值为AUTO_INCREMENT索引字段生成,如果没有索引字段,则为0x00。注意:当INSERT插入语句为多行数据时,该索引ID值为第一个插入的数据行索引值,而非最后一个

status_flags:  服务器状态,客户端可以通过该值检查命令是否在事务处理中

warnings:   告警次数,即告警发生的次数

session state info:  会话状态信息

info:  服务器消息,服务器返回给客户端的消息,一般为简单的描述性字符串,可选字段。

**会话状态信息**

状态变化信息作为一组状态变化块在OK数据包中发送,这些状态变化块由以下部分组成:

类型:数据的类型,可以查看 enum_session_state_type.。 数据,会话信息改变的数据

 

enum enum_session_state_type {
  SESSION_TRACK_SYSTEM_VARIABLES, /**< Session system variables */
  SESSION_TRACK_SCHEMA,           /**< Current schema */
  SESSION_TRACK_STATE_CHANGE,     /**< track session state changes */
  SESSION_TRACK_GTIDS,            /**< See also: session_track_gtids */
  SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /**< Transaction chistics */
  SESSION_TRACK_TRANSACTION_STATE            /**< Transaction state */
};

 数据字段的解释取决于类型值。

1)、SESSION_TRACK_SYSTEM_VARIABLES   会话跟踪系统变量

2)、SESSION_TRACK_SCHEMA  会话跟踪模式

3)、SESSION_TRACK_STATE_CHANGE 会话跟踪状态更改。 指示会话状态是否发生更改的标志字节。此标志表示为ASCII值

2、ERR 响应报文 

错误包意味着产生了错误信息,在 MySQL4.1版本之后,它包含一个 SQL 状态值,错误文本大小不能超过 Error texts cannot exceed。 代码函数 net_send_error_packet()

header: 消息头,ERR 报文问 0xFF

error-code:  错误码,定义在源代码/include/mysqld_error.h头文件中

sql_state_marker:  服务器状态标志,恒为'#'字符

sql_sate: 服务器状态,服务器将错误编号通过mysql_errno_to_sqlstate函数转换为状态值,状态值由5字节的ASCII字符组成,定义在源代码/include/sql_state.h头文件中

error_message: 错误信息,错误消息字符串到达消息尾时结束,长度可以由消息头中的长度值计算得出。消息长度为0-512字节

3、EOF 响应报文 

如果启用了CLIENT_PROTOCOL_41,则EOF数据包包含警告计数和状态标志。

在 mysql 的通信协议中,EOF 数据包和 OK 数据包是一样的目的,用来标记一个查询结果的结束。在 MySQL5.7因为 OK 数据包发生了更改(如会话状态跟踪),为了避免 EOF 数据发生重复更改,在 MySQL5.7.5之后弃用 OK 数据包。

EOF_数据包可能出现在可能出现Protocol::engthCodedInteger的地方。您必须检查数据包长度是否小于9,以确保它是EOF_数据包。

warnings: 告警计数,服务器告警数量,在所有数据都发送给客户端后该值才有效。

status_flags: 状态标志位,包含类似SERVER_MORE_RESULTS_EXISTS这样的标志位。

:由于EOF值与其它Result Set结构共用1字节,所以在收到报文后需要对EOF包的真实性进行校验,校验条件为:

  • 第1字节值为0xFE
  • 包长度小于9字节

未完待续。。。。