- 将数据分成大小为(2^24−1)字节的数据包
- 给每个数据块加上一个包头
由于连接的创建和释放都需要耗费资源,所以数据库这种交互频繁,且连接数量不需要特别大的应用场景,一般使用长连接。
使用短连接尚能通过RST判断数据是否读完了,而长连接就不能这么做了,同时由于TCP的特点,数据读写会发生拆包、粘包。所以使用长连接传输数据,必须通过某种方法把要发送的数据告诉接收方。例如HTTP协议head里的CONTENT-LENGTH。也可以通过特殊的符号判断,不过由于消息里可能也会出现这些符号,会发生歧义,所以应用场景受限。还有一种最简单的方法就是每次发送固定长度消息,不够用0填充。
MySQL数据包结构
Type | Name | Description |
---|---|---|
int<3> | payload_length |
payload的长度,整数类型。不包括包头四个字节 |
int<1> | sequence_id |
Sequence ID |
string | payload |
有效载荷,字符串类型。长度=payload_length |
消息包分为两个部分,包头+包体。
包头固定四个字节,前三个字节是整数型的payload长度,第四个是整数型的消息序列号。
包体就是这个包的有效载荷,长度由前三字节指定,内容根据具体场景各不相同。
例如,一个消息为03 00 00 01 01 02 03 04
。先读取前四个字节,发现这个消息包体有3个字节,这个消息序号是0,消息内容是01 02 03
,后面的04
是下一个包的数据。
包体长度
由于包体长度是由三个字节记录的,三个字节能表示的最大值为FF FF FF
,即1<24-1
=2^24-1
=16777215
=15.999...
M。所以,一个MySQL消息包体不能超过16MB。如果超过16MB,就分多次发送。
消息序号
消息号用来标记每个消息的顺序,会自动增长,并循环。
通用响应包
对于大多数请求,服务端有一些通用的响应包结构。
OK_Packet
命令成功完成后的响消息。
Type | Name | Description |
---|---|---|
int<1> | header |
[00] 或 [fe] |
int |
affected_rows |
affected rows 影响行数 |
int |
last_insert_id |
last insert-id 最后插住数据id |
if capabilities & CLIENT_PROTOCOL_41 { |
||
int<2> | status_flags |
Status Flags |
int<2> | warnings |
警告数量 |
} else if capabilities & CLIENT_TRANSACTIONS { |
||
int<2> | status_flags |
Status Flags |
} | ||
if capabilities & CLIENT_SESSION_TRACK { |
||
string |
info |
容易理解的状态信息 |
if status_flags & SERVER_SESSION_STATE_CHANGED { |
||
string |
session_state_changes |
session state info |
} | ||
} else { | ||
string |
info |
容易理解的状态信息 |
} |
header:表明这是一个OK还是EOF响应。
capabilities :在创建连接阶段,客户端和服务端交换的字段,用于表示支持哪些特性。
CLIENT_PROTOCOL_41:4.1+版本的客户端使用的协议。
ERR_Packet
Type | Name | Description |
---|---|---|
int<1> | header |
[ff] |
int<2> | error_code |
错误码 |
if capabilities & CLIENT_PROTOCOL_41 { |
||
string[1] | sql_state_marker |
# marker of the SQL State |
string[5] | sql_state |
SQL State |
} |
||
string |
error_message |
容易理解的错误信息 |