mysql源码剖析–通信协议分析
引言
我们使用驱动连接mysql服务器,其协议通常以TCP/IP为主;此外,mysql还支持命名管道等方式交互。无论底层通道是什么,mysql都在其上建立了统一的应用协议。
1 交互过程
以TCP/IP为例,整个mysql客户与服务器交互过程如下:
1.1 认证阶段
认证阶段由服务器发起随机挑战数据给客户端;客户端加密挑战数据和口令,封装成认证请求给服务器;最后,服务器验证挑战请求、返回OK或ERROR。
1.2 服务阶段
服务阶段由客户端发起命令请求;服务器响应命令,响应命令的返回分为两种:
- 带状态的返回:对于增删改操作,返回OK或ERROR包
- 结果集的返回:当查询数据且处理成功的情况,依次返回结果头包、若干个列信息包、EOF包、若干个行数据包、EOF包;特别地,当查询命令失败返回ERROR包
1.3 退出阶段
退出阶段本质上是客户端发送退出命令请求(与服务器阶段的命令采用相同格式封装)、服务器响应退出命令并释放资源。
2 协议简介
mysql对所有的消息采用一个通用的模式进行包装,即:
其中3字节的数据长度,1字节的包序号。每次请求或响应,包序号从1开始依次递增,直到最后一个序号的数据长度小于16M。数据内容如下:
2.1 server->client握手协议
握手协议是服务器在tcp连接建立后,向客户端发送的认证挑战。其相关字段如下:
- protocol_version:服务器协议版本号。
- server_version:服务器的版本号。
- conn_thread_id:服务器为客户端分配。
- before_scramble_data:服务器生成的随机挑战数据的前8个字节。
- 0x00:填充值
- client_capabilities:期望客户端访问的能力低两个字节。
- charset_num:字符编码号。
- server_status:服务器状态。
- client_capabilities:期望客户端访问的能力高两个字节。
- scramble_len: 挑战数据总长
- 0x00:填充值
- after_scramble_data:服务器生成的随机挑战数据的剩余字节。
- plugin_name:MPVIO_EXT插件的名称
注:相关代码在文件sql/sql_acl.cc的函数send_server_handshake_packet中
2.2 client->server认证协议
认证协议是客户端根据服务端的随机挑战数据通过系列哈希算法生成的认证请求。
当客户端协议版本大于等于4.1,其相关字段如下:
- client_capabilities:客户端可以访问的能力低两个字节。
- client_capabilities:客户端可以访问的能力高两个字节。
- max_client_packet_length:客户端最大的包长度。
- charset_code:客户端字符编码。
- 0x00:填充值
- user:用户名
- pw_scramble len:认证哈希数据长度
- pw_scramble:认证哈希数据
- db:数据库名称,可忽略
- client_plugin:客户端端插件名称
当客户端协议版本小于等于4.0,其相关字段如下:
- client_capabilities:客户端可以访问的能力,仅两个字节。
- max_client_packet_length:客户端最大的包长度。
- user:用户名
- pw_scramble len:认证哈希数据长度
- pw_scramble:认证哈希数据
- db:数据库名称,可忽略
- client_plugin:客户端端插件名称
注:相关代码在文件sql/sql_acl.cc的函数parse_client_handshake_packet中
2.3 server->client OK
OK协议是服务器对客户端发来的请求处理通过的反馈。
当客户端协议版本大于等于4.1,其相关字段如下:
- 0x00:填充值。
- affected_rows:受影响的行数,对于增删改有效。
- index_id:索引ID,对于自增型索引插入有效。
- server_status:服务器状态。
- statement_warn_count:警告累计次数。
- message:反馈消息。
当客户端协议版本小于等于4.0,其相关字段如下:
- 0x00:填充值。
- affected_rows:受影响的行数,对于增删改有效。
- index_id:索引ID,对于自增型索引插入有效。
- server_status:服务器状态。
- message:反馈消息。
注:相关代码在文件sql/protocol.cc的函数net_send_ok中
2.4 server->client ERROR
OK协议是服务器对客户端发来的请求产生处理错误的反馈。
当客户端协议版本大于等于4.1,其相关字段如下:
- 0xff:填充值。
- sql_errno:错误编号。
- ‘#’:错误消息信息字符。
- sqlstate:错误状态:
- converted_err:错误消息。
当客户端协议版本小于等于4.0,其相关字段如下:
- 0x00:填充值。
- sql_errno:错误编号。
- converted_err:错误消息。
注:相关代码在文件sql/protocol.cc的函数net_send_error_packet中
2.5 client->server命令请求
当客户端协议版本大于等于4.1,其相关字段如下:
- command:命令类型。
- content:命令内容,不同类型的命令,其内容格式不一致。
2.6 server->client 结果头
结果头是服务器返回给客户端结果集数据的第一个包。
- field_count:列数量
注:相关代码在文件sql/protocol.cc的函数Protocol::send_result_set_metadata中
2.7 server->client 列信息
列信息是服务器给客户端结果集数据列的元信息。
当客户端协议版本大于等于4.1,其相关字段如下:
- 0x03 字符串"def"长度。
- “def”:固定值。
- db_name len:数据库名称字符串长度。
- db_name:数据库名称字符串
- as_table_name len:表的as name字符串长度。
- as_table_name:表的as name字符串。
- org_table_name len:表的原始name字符串长度。
- org_table_name:表的原始name字符串。
- as_col_name len:列的as name字符串长度。
- as_col_name:列的as name字符串。
- org_col_name len:列的原始name字符串长度。
- org_col_name:列的原始name字符串。
- 0x0c:固定值。
- charset_code:字符编码:
- field_length:列数据长度。
- field_type:列类型。
- field_flags:列的flag标志。
- field_decimals:列的小数位数。
- 0x00:填充值。
当客户端协议版本小于等于4.0,其相关字段如下:
- table_name len:表的name字符串长度。
- table_name:表的name字符串。
- col_name len:列的name字符串长度。
- col_name:列的name字符串。
- 0x03:固定值。
- field_length:列数据长度。
- 0x01:固定值。
- field_type:列类型。
- 0x03:固定值。
- field_flags:列的flag标志。
- field_decimals:列的小数位数。
注:相关代码在文件sql/protocol.cc的函数Protocol::send_result_set_metadata中
2.8 server->client EOF
EOF是服务器给客户端结果集数据列的元信息和行数据的结束标志。
当客户端协议版本大于等于4.1,其相关字段如下:
- 0xfe 固定值。
- statement_warn_count:警告累计数目。
- server_status:服务器状态。
当客户端协议版本小于等于4.0,其相关字段如下:
- 0xfe 固定值。
注:相关代码在文件sql/protocol.cc的函数write_eof_packet中
2.9 server->client 行数据
行数据是服务器返回给客户端结果集中的查询行。由若干行行组成,每行一个单独的包。
- col_1_data len:列1数据长度
- col_1_data:列1数据编码。
。。。。。。 - col_n_data len:列n数据长度
- col_n_data:列n数据编码。
注:相关代码在文件sql/protocol.cc的函数Protocol::send_result_set_row中