实现自己的数据库驱动——MySQL协议Handshake解析(三)

前言

在前一篇的博客中,当客户端发送SQL请求到Server端时,产生了一系列Packet。第一个Packet就是本篇要介绍的HandShake。不了解的可以点击上篇博客。

Handshake Packet格式

Handshake packet是由Server向Client发送的初始化包,因为所有从Server向Client端发送的包都是一样的格式,前面的四个字节是包头,其中前三位代表Handshake packet数据长度,第四位是包序列号。下面是Handshake packet具体内容的格式:

相对包内容的位置 长度(字节) 名称 描述
0 1 协议版本 协议版本的版本号,通常为10(0x0A)
1 len = strlen (server_version) + 1 数据库版本 长度为数据库版本字符串的长度+上标示结束的的一个字节
len + 1 4 线程ID 此次连接MySQL Server启动的线程ID
len + 5 8 + 1(0x00表示结束) 挑战随机数(第一部分) 用于后续账户密码验证
len + 14 2 数据库提供的功能 用于与客户端协商通讯方式
len + 16 1 编码格式 标识数据库目前的编码方式
len + 17 2 服务器状态 用于表示服务器状态,比如是否是事务模式或者自动提交模式
len + 19 2 扩展的协议,数据库提供的功能 用于与客户端协商通讯方式
len + 21 1 Authentication Plugin length 身份验证插件长度
len + 22 10 保留字节 未来可能会用到,预留字节
len + 32 12 + 1(0x00表示结束) 挑战随机数(第二部分) 用于后续账户密码验证

在网上查的资料当时保留字节是13位,而我用的MySQL是8.x的,观察我捕获到的包做了点修改,即len+19和len+21位的使用保留字节,所以现在只剩下10个预留字节了。

WireShark分析HandShake Packet

上面的数据格式的描述可能不够具体,所以这里用WireShark来捕获Handshake看看数据是否真如上面所描述的。

你想输入的替代文字

点击Server Greeting proto=10 version=8.0.12 可以看到从Frame物理层到MySQL Protocol应用层各层的具体内容。点击MySQL Protocol可以看到具体的十六进制的内容,以及它的ASCII码。

其中Packet LengthPacket Number就是包的数据头,从上面我们知道,Packet Length是占三个字节的。那么就是说0x00004a表示的就是数据长度,转为十进制发现就是74。

这里有人可能会有疑惑,为什么不是0x4a0000这是因为MySQL采用的是小端存储形式。为什么采用这个形式,可以看最后一段过程中遇到问题的说明。

这里再解释一下Version这个字段,根据上面的描述,我们知道它的长度为数据库版本字符串的长度+上标示结束的一个字节。就是说实际上存储的时候还有一个0x00的字节跟着version字段表示结束符。你会发现有好多这种字段跟上结束符的数据,所以在填充数据的时候,需要把0x00也一起填上。

你想输入的替代文字

有了上面两个字段的解释,我相信每个字段的数据你们都能对应上去了,所以这里就不解释了。

过程中遇到的问题

  1. 为什么会有大小端?为什么采用小端计算机计算会更加方便?

你算加减乘的时候是从高位还是低位开始的?

为什么不从高位开始?因为存在着进位,如果从高位开始,算到后面发现有进位,就要回退到高位处理进位
如果从低位开始,可以一下子算出来。早期的计算机是纸带机,纸带上储存的是2进制数据

如果使用小端储存,做加减乘运算时,计算机的写出头可以一直往一个方向移动,而不用回退写出头处理进位问题。

  1. 既然小端像上面所说的一样有计算方便的优势,为什么还要出现大端呢?

大端也有自己的优势,在判定正负时,符号位固定为第一个字节,容易判断。