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)、如果字符串是数据包的最后一个组成部分,则可以从数据包的总长度减去当前位置来计算其长度。
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数据包包含警告计数和状态标志。
EOF_数据包可能出现在可能出现Protocol::engthCodedInteger的地方。您必须检查数据包长度是否小于9,以确保它是EOF_数据包。
warnings: 告警计数,服务器告警数量,在所有数据都发送给客户端后该值才有效。
status_flags: 状态标志位,包含类似SERVER_MORE_RESULTS_EXISTS
这样的标志位。
注:由于EOF值与其它Result Set结构共用1字节,所以在收到报文后需要对EOF包的真实性进行校验,校验条件为:
- 第1字节值为0xFE
- 包长度小于9字节
未完待续。。。。