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

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

mysql 通信包括,握手连接阶段、命令执行阶段和主从复制协议。在连接执行以下任务,客户端和服务器数据交换,如果请求加密设置 ssl 连接通道,根据服务器对客户端进行身份验证。

服务器和客户端完整交互如下:

1、登录认证交互报文

初始化握手,初始化握手从服务端发送  Protocol::Handshake 包开始,然后客户端可以选择使用 SSL 协议。接着客户端发送 Protocol::HandshakeResponse数据包。

接下来介绍一下 HandshakeV10数据报文,其他版本可以参考源码文档

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

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

thread id:  服务器为当前连接创建的线程 id

auth-plugin-data-part-1: 挑战随机数前8字节(第一部分),MySQL数据库用户认证采用的是挑战/应答的方式,服务器生成该挑战数并发送给客户端,由客户端进行处理并返回相应结果,然后服务器检查是否与预期的结果相同,从而完成用户认证的过程.

filler:  填充值 0x00, 终止挑战随机数前8字节。

capability_flags_1:服务权能标志的低16位

character_set: 字符编码,标识服务器用的字符集。只包含低8位。

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

enum SERVER_STATUS_flags_enum {   SERVER_STATUS_IN_TRANS = 1,      /**< 当使用显示事务活关闭自动提交时会触发*/   SERVER_STATUS_AUTOCOMMIT = 2,   /**< 服务处于自动提交模式 */   SERVER_MORE_RESULTS_EXISTS = 8, /**< 使用 mulit query 时,存在下一条 query */   SERVER_QUERY_NO_GOOD_INDEX_USED = 16, /**< 查询没有使用好的索引 */   SERVER_QUERY_NO_INDEX_USED = 32, /**< 查询没有使用任何索引 */   /**     服务器能够满足客户机的请求,并为查询打开了一个只读的不可滚动游标,此标志用于响应COM_STMT_EXECUTE和COM_STMT_FETCH命令     由二进制协议结果集使用,表示必须使用COM_STMT_FETCH来获取行数据     @todo Refify Binary Protocol Resultset and COM_STMT_FETCH.   */   SERVER_STATUS_CURSOR_EXISTS = 64,   SERVER_STATUS_LAST_ROW_SENT = 128,  /**< 当只读游标耗尽时,法师该标志用来响应COM_STMT_FETCH 命令*/   SERVER_STATUS_DB_DROPPED = 256, /**< 删除一个库 */   SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512,   SERVER_STATUS_METADATA_CHANGED = 1024,  /**< 在一个 prepeaed 语句重复执行 发现新语句返回不同数量的结果集列,将此标记返回给客户端*/   SERVER_QUERY_WAS_SLOW = 2048,    /**< 标记语句是否属于慢查询 */   SERVER_PS_OUT_PARAMS = 4096,   /**< 标记含有输出参数的结果集 */   /**< 如果多语句事务是只读的,则与SERVER_STATUS_IN_TRANS同时设置。事务提交或者终止时清除    由于该标志以OK和EOF数据包的形式发送给客户端,因此该标志指示命令执行结束时的事务状态。*/   SERVER_STATUS_IN_TRANS_READONLY = 8192,     SERVER_SESSION_STATE_CHANGED = (1UL << 14)   /**< 如果启用此状态标志,则表示由于执行了最后一条语句,服务器上的一个状态信息已更改。 */ };

capability_flags_2: 服务权能标志的高16位。与客户端协商通讯方式,各标志位含义如下(参考MySQL源代码/include/mysql_com.h中的宏定义)也可参考源码文档

auth_plugin_data_len: 如果auth_plugin_data_len > 0。组合身份验证插件数据的长度

00: 填充值,标志服务权能标志后八位结束

reserved:保留值都是0

auth-plugin-data-part-2:挑战随机数的第二部分

auth_plugin_name: 认证方法的名称

握手响应:

客户端接收到 handshake 包之后,生成一个响应并发给 server。如果Handshake Packet中的权能标识中带有client_protocol_41标识位,那么客户端将生成的Response为HandShake Response41,否则生成的为HandShake Response320,我们这里就不管HandShake Response320,因为现在的Server基本都会支持这个。

TypeNameDescription
int<4> client_flag Capabilities Flags, CLIENT_PROTOCOL_41 always set.
int<4> max_packet_size maximum packet size   最大消息长度
int<1> character_set client charset a_protocol_character_set, only the lower 8-bits
string[23] filler filler to the size of the handhshake response packet. All 0s.
string<NUL> username login user name
if capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA {
string<length> auth_response opaque authentication response data generated by Authentication Method indicated by the plugin name field.
} else {
int<1> auth_response_length length of auth_response   
string<length> auth_response opaque authentication response data generated by Authentication Method indicated by the plugin name field.
}
if capabilities & CLIENT_CONNECT_WITH_DB {
string<NUL> database initail database for the connection. This string should be interpreted using the character set indicated by character set field.
}
if capabilities & CLIENT_PLUGIN_AUTH {
string<NUL> client_plugin_name the Authentication Method used by the client to generate auth-response value in this packet. This is an UTF-8 string.
}
if capabilities & CLIENT_CONNECT_ATTRS {
int<lenenc> length of all key-values affected rows
string<lenenc> key1 Name of the 1st client attribute
string<lenenc> value1 Value of the 1st client attribute
.. (if more data in length of all key-values, more keys and values parts)
}
int<1> zstd_compression_level compression level for zstd compression algorithm

注:如果客户端和服务器版本不匹配,可能有其他情况发生,如果验证方法不匹配。服务器和客户端进行不同的处理。如AuthSwitchRequest请求,包括验证方法的介绍,请参考源码文档。

接下来为命令阶段:请参考http://hutaow.com/blog/2013/11/06/mysql-protocol-analysis/#1