目录
字符串(以NULL结尾)(Null-Terminated String)
二进制数据(长度编码)(Length Coded Binary)
字符串(长度编码)(Length Coded String)
--Row Data 结构 / 二进制Row Data 结构
最近工作关系,想能不能增加mysql每次传输数据的行数来提升传输数据性能。
所以最近开始研究mysql的数据传输协议。
mysql客户端与服务端的认证流程
连接方式
mysql的主要连接方式有几种:
SOCKET连接(Linux)
目标 启动选项 默认值
SERVER --enable-named-pipe --socket=SOCKET /tmp/mysql.sock
CLIENT --protocol=SOCKET --socket=SOCKET /tmp/mysql.sock
在Linux和Unix环境下,可以使用Unix套接字进行Mysql服务器的连接;Unix套接字其实不是一个网络协议,只能在客户端和Mysql服务器在同一台电脑上才可以使用
PIPE连接(Windows)
目标 启动选项 默认值
SERVER --enable-named-pipe --socket=SOCKET MYSQL
CLIENT --protocol=PIPE --socket=SOCKET MYSQL
在window系统中客户端和Mysql服务器在同一台电脑上,可以使用命名管道的方式,
SHARED MEMORY连接(Windows)
目标 启动选项 默认值
SERVER --shared-memory --shared-memory-base-name=MEMORY MySQL
CLIENT --protocol=MEMORY --shared-memory-base-name=MEMORY MySQL
在window系统中客户端和Mysql服务器在同一台电脑上,可以使用共享内存的方式,
TCP连接(Linux,Windows)
目标 启动选项 默认值
SERVER --port=PORT 3306
CLIENT --protocol=TCP --port=PORT 3306
任何系统下都可以使用的方式,也是使用的最多的方式。
其实熟悉操作系统的朋友应该能体会出来,像前两种,因为客户端和服务端在同一台主机上,也就是一台主机的两个应用,所以这也就是进程间通信的方式,而在不同的主机上就不一样了,就需要网络,tcp/ip建立了。
通信过程
在生产环境中,常用的肯定是tcp连接方式,不光适配windows和linux,而且能用于多台主机。除非产品抗压需求不高,不然客户端和服务端不会放到一台机子上的。
那么主要来学习mysql使用tcp的连接。
Mysql是一个c/s架构的软件,所以有服务端和客户端。
在使用mysql客户端时,会通过bin目录下的mysql可执行文件启动。
比如使用: ./mysql -hhost -Pport -uusername -ppassword 。
这时会创建并启动一个新的mysql客户端进程。
使用ps aux|grep mysql 可以查看到:
那么在使用这个命令时,干了哪些事?
mysql客户端与服务端通信是基于tcp来连接的,所以第一步就是经历三次握手,建立tcp连接。
在建立好tcp连接后,就开始进行握手认证阶段。
握手认证阶段为客户端与服务器建立连接后进行,交互过程如下:
服务器 -> 客户端:握手初始化消息
客户端 -> 服务器:登陆认证消息
服务器 -> 客户端:认证结果消息
为什么要进行三次握手认证?
因为tcp三次握手,只是将客户端与服务端建立起了连接,然后通过端口知道我要访问的是mysql这个服务,但是mysql它不同于http,只要你知道url就能得到一个响应,mysql必须登陆后你才能进行操作。所以这个过程最重要的就是验证客户端的登陆权限。
为什么是服务端主动给客户端发送认证呢?
http不是说只有客户端主动与服务端进行请求,服务端不是不能在没有请求的情况下主动进行响应吗?
首先,大家也不要陷入误区,在进行认证的这个交互中,实际上客户端与服务端还没有进行任何业务上的往来,只是进行一个认证,所以与上面说的http的不同,如果细心的话你会发现,认证成功后,在命令执行阶段,mysql这种通信方式是与http非常类似的,在没有请求的情况下,服务端的mysql也不会主动给你发送任何数据,所以这里不要混淆。
再说为什么服务端先发送,那肯定是因为他有不得不发送的道理,所以我们就需要理解一下,他发送的是什么东西。
第一次握手报文
基于mysql5.1.73(mysql4.1以后的版本)
第一次握手报文也就是服务端向客户端发送的握手初始化报文。
- 协议版本号:服务端所使用的mysql协议的版本号,该值由 PROTOCOL_VERSION 宏定义决定(参考MySQL源代码
/include/mysql_version.h
头文件定义) - 服务版本信息:该值为字符串,由 MYSQL_SERVER_VERSION 宏定义决定(参考MySQL源代码
/include/mysql_version.h
头文件定义) - 服务器线程ID:服务端为此客户端所创建的线程的ID
- 挑战随机数:MySQL数据库用户认证采用的是挑战/应答的方式,服务器生成该挑战数并发送给客户端,由客户端进行处理并返回相应结果,然后服务器检查是否与预期的结果相同,从而完成用户认证的过程。
- **服务器权能标志:**用于与客户端协商通讯方式(参考MySQL源代码
/include/mysql_com.h
中的宏定义) -
字符编码:标识服务器所使用的字符集。
-
服务器状态:状态值定义如下(参考MySQL源代码
/include/mysql_com.h
中的宏定义):-
状态名称 状态值 SERVER_STATUS_IN_TRANS 0x0001 SERVER_STATUS_AUTOCOMMIT 0x0002 SERVER_STATUS_CURSOR_EXISTS 0x0040 SERVER_STATUS_LAST_ROW_SENT 0x0080 SERVER_STATUS_DB_DROPPED 0x0100 SERVER_STATUS_NO_BACKSLASH_ESCAPES 0x0200 SERVER_STATUS_METADATA_CHANGED 0x0400
-
第二次握手报文
第二次握手报文也就是客户端向服务端发送的登录认证报文。