Advertisement

MySQL 通信协议介绍

阅读量:

MySQL 通信协议介绍

1、数据类型

了解MySQL协议包之前必需先知道其数据类型

1.1 Integer Types 整数类型

(1)定长整型

固定长度, 小端编码, 有下面几种(括号内的代表所占字节数):

int<1>

int<2>

int<3>

int<4>

int<6>

int<8>

(2)变长整型

可能长度为1, 3, 4, 9 个字节, 实际长度取决于数值的大小.记为 int

编码过程, 记数值为N:

1.若 N < 251, 则编码为单字节

2.若 251 <= N < 2^16, 则编码为 0xfc + 2-byte integer

3.若 2^16 <= N < 2^24, 则编码为 0xfd + 3-byte integer

4.若 2^24 <= N < 2^64, 则编码为0xfe + 8-byte integer

解码过程, 先看第一个字节, 记其值为N1,

1.若 N1 <= 0xfb, 则说明该整数就是N1

2.若 N1 = 0xfc,则说明接下来2字节也是该整数的部分, 取出加上0xfc即为原数值

3.若 N1 = 0xfd, ...

4.若 N1 = 0xfe, ...

需要注意的是,在一个协议包的第一个字节等于0xfe时,则应检查后续是否包含8个字节;若后续未包含8个字节,则该协议包可能属于结束标志数据包(EOF_PACKET)。

1.2 String Types 字符串类型

(1)FixedLengthString

定长字符串,记为 string

(2)NulTerminatedString

由NUL标识结束的字符串, NUL即0x00,记为string

(3)VariableLengthString

动态长度字符串的长度基于其他字段或在运行时动态计算得出,并表示为string

(4)LengthEncodedString

采用长度编码表示法表示的字符串中,在开头有一个整型int字段用于指示后续字符串的实际长度。其中该编码类型被命名为VariableLengthString,并记作string

(5)RestOfPacketString

当某个字符串是协议包末尾的一个字段时, 那么该字符串的长度自然就等于包长减去当前位置, 并记为string

2.MySQL协议包

客户端或服务端要发消息给对方时:

1.把消息分成若干个长度小于 2^24-1(即16 M)的消息

2.给每个消息前面加一个4字节包头.

如下:

Type Name Description
int<3> payload_length payload字段的长度
int<1> sequence_id 序列号
string payload payload包体

例如CMD_QUIT的整包字节序列为:01 00 00 00 01

1.通用响应报文

(1) OK_Packet

表示操作成功的报文,5.7开始用该报文替代EOF_Packet

报文格式:

判断时OK还是EOF规则:

OK: header = 0 and length of packet > 7

EOF: header = 0xfe and length of packet < 9

(2) ERR_Packet

指示操作失败的状态信息. Only when the CLIENT_PROTOCOL_41 capability feature is enabled, the message will include a SQL state value.

报文格式:

(3) EOF_Packet

When the CLIENT_PROTOCOL_41 capability flag is enabled, the EOF packet includes a warning count and status flags.

EOF报文用于标识由多个报文组成的报文簇的结束位置,在数据库系统中通常用于管理事务操作的安全性。例如,在MySQL服务器中,当客户端向其发送一个查询指令时(即发起一个查询请求),MySQL将按照预定顺序依次返回一系列相应的响应数据流(即分片)。

  1. ResultSetHeaderPacket — 在报文字段中携带了查询结果中的字段个数N以及还包括其他相关信息

2.FieldPacket * N -- N个FieldPacket,每一个都表示一个字段的定义

3.EOF Packet -- 表示字段定义的所有报文已发送完毕

4.RowDataPacket * M -- 每个报文表示一行数据

5.EOF Packet -- 表示行数据报文发送完毕。

报文格式:

End_of_File_PACKET和OK_PACKET均用于标识...查询结果的尾部数据包;自5.7.5版本起...该类型的数据包已不再被使用

上面的报文中涉及到的statu_flag取值及含义如下:

2.连接建立阶段报文

(1) Handshake Packet(Server - > Client)

当客户端发起与服务端的通信请求时,在建立通信链路完成之后(即TCP连接建立完成后),服务器会通过发送一份初始连接报文向客户端发起邀请(即握手)。这份初始连接报文包含了服务器的基本信息以及相应的权限标识(即capabilities flag)。其中关于权限标识的具体内容,请参阅此处以获取详细信息。

Java代码

  1. 协议版本号为1的[0a]格式
  2. 服务器端的版本号为NUL字符串
  3. 第4个连接ID字段
  4. 长度固定的字符串[8]用于身份验证插件的数据部分1
  5. 填充字段由一个固定值0x00组成
  6. 在服务器端决定权限标志位下2位的状态
  7. 当接收到的数据包中还有更多数据时:
    a. 如果具备客户端插件中的授权标志位,则表示客户端插件的身份验证数据长度
    b. 否则填充字段由一个固定值空字节组成
    c. 设定标识符长度字段以记录身份验证插件数据的实际长度
    d. 在具备客户端插件中的授权标志位时设定身份验证插件名称字段

(2)HandShake Response Packet(Client - > Server)

客户端接收到handshake packet后,向server发送出去一个response,其中包含客户端的权限标识符、用户名等信息.若handshake packet中权限标识符包含了client protocol 41标志位,则该客户端会发送handshake response 41;反之则会发送handshake response 320.鉴于大多数服务器已配备该功能,此处我们不再处理handshake response 320

HandShake Response41格式:

Java代码

  1. 客户端系统中设置了4个权限标志位(CLIENT_PROTOCOL_41),这些标志位始终被设置为已启用状态。
  2. 最大包大小设为4字节。
  3. 字符集长度设为1。
  4. 引用字符串(length of all key-values)字段全部置空后赋值给username变量。
  5. 当客户机具备AUTH-PLUGIN授权时,在连接数据库时会自动启用密码验证功能。
  6. 在客户机插件中定义了多个字符编码方案(encodings),其中包含ASCII编码方案。

3.普通请求/响应报文

在连接建立完成后,Client之后即可发送常规查询指令或其他操作指令给Server。接下来将详细讲解这些指令。

1.COM_SLEEP 请求

这个是Server内部的命令,不是客户端给服务端发的,忽略即可

Java代码

  1. 1 [00] COM_SLEEP

2.COM_QUIT 请求

当客户端要关闭连接时,发送该命令到Server

Java代码

  1. 1 [01] COM_QUIT

返回:要么是OK Packet,要么就连接关闭

3.COM_INIT_DB 请求

修改连接默认的schema

Java代码

  1. 1 [02] COM_INIT_DB
  2. string[EOF] schema name -- 数据库名

返回:OK Packet 或者ERR Packet

4.COM_QUERY 请求

提交普通查询请求时,请注意该查询属于即时执行类型。因此不需在编译阶段处理此命令。

Java代码

  1. 1 [03] COM_QUERY
  2. string[EOF] the query the server shall execute -- sql语句

返回:COM_QUERY_RESPONSE Packet

5.COM_QUERY_PACKET 响应

对于COM_QUERY这一查询指令生成的响应报文而言,在此过程中仅会输出对应的结果集合信息这一种情况

  • Error Code Packets
    • OK Message or OK Data Frame
    • Common Query Result Set Packets -- 常见查询结果集
    • Data Loading In-File Request Message or In-File Request Data Frame

6. Result Set Packet 响应 普通的查询响应也是一个逻辑上定义的报文,并且它由以下几个组成部分构成:它包括数据字段、字段值、元数据以及相关的元数据信息。

1.ResultSetHeaderPacket -- 仅由带有标记位的信息(N)和8-byte length的补充数据组成。

  1. ColumnDefinitionPacket * N表示N个ColumnDefinitionPacket ,每一个ColumnDefinitionPacket表示一个字段的信息 ,其格式如下。

Java代码

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的改写

以下是根据给定规则对原文的修改

  1. 当收到EOF包时表示所有ColumnDefinition包已发送完毕,接下来即将开始处理数据传输。

4.任意数量的RowDataPacket都有所对应的具体信息。每个RowDataPacket都对应一行数据。其中 NULL 值以字节 0xfb(即十进制 251)进行编码。具体格式请参考下文

Java代码

该字符串在第1个字段中的数据值为:...
该字符串在第2个字段中的数据值为:...
...
该字符串在第N个字段中的数据值为:...

  1. 结束标记包(EOF Packet),表示对应的Result Set已经结束。如果接收到的该数据包中包含了SERVER_MORE_RESULT_EXISTS字段的标志位为真,则也即说明后续还会再发送一个Result Set Packets,请返回到最初步骤继续接收...

整个查询过程如下图:

7.COM_FIELD_LIST 请求

获取字段定义,5.7.11开始已弃用

Java代码

1 [04] COM Field List
2 null type string table -- 表名
3 string[EOF] field pattern 字段通配符

返回:COM_FIELD_LIST RESPONSE Packet

8.COM_FIELD_LIST 响应

COM_FIELD_LIST的响应报文,该报文是一个逻辑报文,其组成为以下一种:

1.ERR packet

2.任意个ColumnDefinitionPacket加一个EOFPacket

9.COM_CREATE_DB 请求

创建数据库请求

Java代码

  1. 1 [05] COM_CREATE_DB
  2. string[EOF] schema name -- 数据库名

返回:OK Packet或者ERR Packet

10.COM_DROP_DB 请求

删除数据库请求

Java代码

  1. 1 [06] COM_DROP_DB
  2. string[EOF] schema name -- 数据库名

返回:OK Packet 或者 ERR Packet

11.COM_REFRESH 请求

flush和reset...指令的命令实现自5.7.11版本起不再提供该功能,改用COM_QUERY函数来执行flush操作

Java代码

  1. 1 [07] COM_REFRESH
  2. 1 sub_command -- 命令,取值见下

sub_command取值:

返回:OK Packet或者ERR Packet

12.COM_SHUTDOWN 请求

关于关闭MySQL服务器的请求中提到5.7.9版本已被废弃使用8.0及以后版本则无法执行该命令建议更新至最新版本以避免相关问题

Java代码

  1. 1 [08] COM_SHUTDOWN
  2. if more data {
  3. 1 shutdown type
  4. }

shutdown type取值:

返回:OK Packet或者ERR packet

13.COM_STATISTICS 请求

显示人易读的MySQL服务器统计信息,在执行mysqladmin status时输入该命令

Java代码

  1. 1 [09] COM_STATISTICS

返回:string

14.COM_PROCESS_INFO 请求

请列出当前活跃的线程。当执行"显示过程列表"或发送"获取进程列表信息"命令时,请提供该命令。

Java代码

  1. 1 [0a] COM_PROCCESS_INFO

返回:ResultSetPacket 或者ERR Packet

15.COM_CONNECT 请求

mysql server 内部命令,5.7.11版本弃用,使用COM_QUERY替代

16.COM_PROCESS_KILL 请求

关闭连接

Java代码

  1. 1 [0c] COMMUNICATION PROCESS TERMINATED
  2. 4 connection identifier -- 连接标识符,在Handshake packet被传输过来

返回:OK Packet或者ERR Packet

16.COM_DEBUG 请求

When the COM_DEBUG trigger is activated, it generates a detailed report of the internal debug information, which is then outputted to the standard output of the mysql-server. The SUPER user must be granted access to perform this operation. issuing this command during a mysqladmin debug session will ensure that all operations are logged properly.

Java代码

  1. 1 [0d] COM_DEBUG

返回:EOF Packet或者ERR Packet

17.COM_PING 请求

心跳检测

Java代码

  1. 1 [0e] COM_PING

返回:OK Packet

18.COM_TIME

mysql server内部命令

19.COM_DELAYED_INSERT

mysql server内部命令

20.COM_CHANGE_USER 请求

更新当前连接中的用户信息并将其相关设置归零;操作包括更新相关参数、清除工作区表以及清除预先编译的SQL语句等步骤

Java代码

  1. COM_CHANGE_USER
  2. user_id
  3. 如果具备权限并成功建立安全连接{
  4. auth_response_length
  5. auth_response的内容
  6. }否则{
  7. auth_response为空字符串
  8. }
  9. schema_name为空字符串
  10. 当存在更多数据时{
  11. 第2个字符集
  12. 如果具备权限并成功加载客户端插件认证{
  13. auth插件名称为空字符串
  14. }否则{
  15. 如果具备权限并成功加载客户端连接属性{
  16. lenenc_int为所有键值对的数量
  17. lenenc_str表示各个键及其值的数量和长度
  18. 如果'长度'字段中存在更多数据,则表示有更多的键值对出现
  19. }
  20. }

21.COM_RESET_CONNECTION 请求

Re-set the session state; it is lighter in functionality compared to COMCHANGEUSER as it avoids closing and reopening the connection, while also avoiding the need for re-authentication.

Java代码

  1. 1 [1f] COM_RESET_CONNECTION

返回:OK Packet或者ERR Packet

22.COM_DAEMON 请求

mysql server内部命令

23.COM_STMT_PREPARE 请求

预编译语句,执行conn.preparedStatement(sql)时发送该命令

Java代码

  1. 1 the COM_STMT_PREPARE command
  2. string query statement -- sql语句

返回:COM_STMT_PREPARED OK Packet或者Err Packet

24.COM_STMT_PREPARE Response 响应

预编译成功时的响应报文,时逻辑报文,其由多个报文组成:

1.第一个报文包含预编译成功信息,其格式如下:

Java代码

1状态项,[00]表示有效值--成功标志位
4statement_id--预先编译的标识符
字段数量为2--
参数数量为2--
保留状态始终设置为[空]--
警告数量设定为2--

如果上面的参数个数(记为N)大于0的话,则表示接下来会依次传输N个ColumnDefinitionPacket,并随后发送一个EOF Packet。

当字段数量为MM>0时(即非零情况下),随后将发送M个ColumnDefinitionPacket以及一个EOF Packet

25.COM_STMT_SEND_LONG_DATA请求

当预编译阶段存在多个项时,
就需提供相应的请求信息,
这些请求都必须在COM_STMT.Execute之前的步骤中完成。

Java代码

  1. COM_STMT_SEND_LONG_DATA[18]
  2. statement-id -- 预编译确定的语句标识符
  3. param-id -- 参数标识符
  4. data -- 参数值

返回:无返回

26.COM_STMT_EXECUTE请求

执行预编译语句

Java代码

1个COM_STMT.Execute
4个stmt-id -- 语句ID
一个flags
四个iteration-count, 始终等于一
如果num-params大于零:
定义一个NULL-bitmap变量, 其长度为(num-params+7)除以八的结果
定义一个新的new-params-bound-flag变量
描述每个参数的数据类型, 长度为num-params乘以二的结果
给出每个参数的具体数值

flags取值:

返回:COM_STMT_EXECUTE Response

27.COM_STMT_EXECUTE Response响应

COM_STMT_EXECUTE 的响应报文,是下面三者之一:

1.OK Packet -- 执行update时

2.Err Packet

3.Binary Protocol ResultSet Packet --执行查询时

Binary Protocol ResultSet

binary protocol result和之前讲的ResultSetPacket相似,

28.COM_STMT_CLOSE请求

关闭预编译语句,该请求无响应

Java代码

  1. 1 [19] COM_STMT_CLOSE
  2. 4 statement-id -- 预编译语句ID

29.COM_STMT_RESET请求

清除由COM_STMT_SEND_LONG_DATA传输的所有参数,并释放由COM_STMT.Execute打开的CURSOR

Java代码

  1. 1 [1a] COM_STMT_RESET
  2. 4 statement-id

返回:OK Packet或者ERR Packet

// TODO 未完待补充

全部评论 (0)

还没有任何评论哟~