IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> mysql握手链接,服务端到底发过来了什么? -> 正文阅读

[大数据]mysql握手链接,服务端到底发过来了什么?

目录

mysql客户端与服务端的认证流程

连接方式

通信过程

第一次握手报文

第二次握手报文

第三次握手报文

服务端->客户端,响应报文

报文结构

报文数据基本类型

整型值

字符串(以NULL结尾)(Null-Terminated String)

二进制数据(长度编码)(Length Coded Binary)

字符串(长度编码)(Length Coded String)

OK响应报文

ERROR响应报文

EOF响应报文

Result Set 响应报文

--Result Set Header 结构

--column definitions?结构?

--Row Data 结构 / 二进制Row Data 结构

LOCAL INFILE 响应报文

参考


?最近工作关系,想能不能增加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_TRANS0x0001
      SERVER_STATUS_AUTOCOMMIT0x0002
      SERVER_STATUS_CURSOR_EXISTS0x0040
      SERVER_STATUS_LAST_ROW_SENT0x0080
      SERVER_STATUS_DB_DROPPED0x0100
      SERVER_STATUS_NO_BACKSLASH_ESCAPES0x0200
      SERVER_STATUS_METADATA_CHANGED0x0400

第二次握手报文

第二次握手报文也就是客户端向服务端发送的登录认证报文。

  • 客户端权能标志:客户端收到服务器发来的初始化报文后,会对服务器发送的权能标志进行修改,保留自身所支持的功能,然后将权能标返回给服务器,从而保证服务器与客户端通讯的兼容性。
  • 消息长度:客户端发送请求时所支持的最大消息长度值
  • 字符编码:表示通讯过程中使用的字符编码,与服务器在认证报文中发送的相同
  • 用户名:客户端登陆的用户名
  • 挑战认证数据:客户端用户密码使用服务器发送的挑战随机数进行加密后,生成挑战认证数据,返回给服务器用于服务端的认证
  • 数据库名称:当客户端的权能标志位 CLIENT_CONNECT_WITH_DB 被置位时,该字段必须出现。

第三次握手报文

第三次握手报文就是服务端发给客户端的认证结果。

?这个就比较好理解了,服务端主要验证,用户名,密码是否正确存在,如果都是正确的,就返回ok报文,错误的话就是ERROR报文。

所以整个客户端和服务端的交互流程如下:

?

服务端->客户端,响应报文

来源于mysql的官方文档。

报文结构

报文分为消息头和消息体两部分,其中消息头占用固定的4个字节,消息体长度由消息头中的长度字段决定,报文结构如下:

  • 消息头:由消息长度和序号构成
  • 消息长度:标记当前请求消息的实际数据长度值,以字节为单位,占用3个字节,最大值为 0xFFFFFF,即接近 16 MB 大小(比16MB少1个字节)
  • 序号:在一次完整的请求/响应交互过程中,用于保证消息顺序的正确,每次客户端发起请求时,序号值都会从0开始计算
  • 消息体:用于存放请求的内容及响应的数据,长度由消息头中的长度值决定

报文数据基本类型

每个消息体都是由多个这些基本类型来构建的。

整型值

MySQL报文中整型值分别有1、2、3、4、8字节长度,使用小字节序传输。

字符串(以NULL结尾)(Null-Terminated String)

字符串长度不固定,当遇到'NULL'(0x00)字符时结束。

二进制数据(长度编码)(Length Coded Binary)

数据长度不固定,长度值由数据前的1-9个字节决定,其中长度值所占的字节数不定,字节数由第1个字节决定,如下表:

第一个字节值后续字节数长度值说明
0-2500第一个字节值即为数据的真实长度
2510空数据,数据的真实长度为零
2522后续额外2个字节标识了数据的真实长度
2533后续额外3个字节标识了数据的真实长度
2548后续额外8个字节标识了数据的真实长度

字符串(长度编码)(Length Coded String)

字符串长度不固定,无'NULL'(0x00)结束符,编码方式与上面的 Length Coded Binary 相同。

来大概看一下mysql服务端给客户端的响应流程:

?

当客户端发起认证请求或命令请求后,服务器会返回相应的执行结果给客户端。客户端在收到响应报文后,需要首先检查类型标识符,来区分响应报文的类型

可以看出,mysql的通用返回包共有几种类型:

  • ERR_Packet
  • OK_Packet
  • EOF_Packet
  • LOCAL INFILE Request
  • Text Resultset

下面开始逐个介绍不同的报文类型。?

OK响应报文

当用户发出的命令成功执行时,会返回一个ok响应报文。

检查当前第一个字节的数据,发现为0x00,那么此时的报文就是一个OK响应报文。

在确定当前报文为OK报文后,之后的结构如下:

字节说明
1OK报文,值恒为0x00
1-9受影响行数(Length Coded Binary),当执行INSERT/UPDATE/DELETE语句时所影响的数据行数。基本类型为一个二进制数据。
1-9索引ID值(Length Coded Binary),该值为AUTO_INCREMENT索引字段生成,如果没有索引字段,则为0x00。注意:当INSERT插入语句为多行数据时,该索引ID值为第一个插入的数据行索引值,而非最后一个。基本类型为一个二进制数据。
2服务器状态,客户端可以通过该值检查命令是否在事务处理中。为2字节的整数。
2告警计数,告警发生的次数。为2字节的整数。
n服务器消息(字符串到达消息尾部时结束,无结束符,可选),返回给客户端的消息,一般为简单的描述性字符串,可选字段。为NULL结尾字符串类型。

ERROR响应报文

当用户发出的命令执行报错时,会返回一个ERROR响应报文。

检查当前第一个字节的数据,发现为0xFF,那么此时的报文就是一个ERROR响应报文。

在确定当前报文为ERROR报文后,之后的结构如下:

字节说明
1Error报文,值恒为0xFF
2错误编号(小字节序),错误编号值定义在源代码/include/mysqld_error.h头文件中。
1服务器状态标志,恒为'#'字符
5服务器状态(5个字符),服务器将错误编号通过mysql_errno_to_sqlstate函数转换为状态值,状态值由5字节的ASCII字符组成,定义在源代码/include/sql_state.h头文件中。
n服务器消息,错误消息字符串到达消息尾时结束。

ERROR的种类非常丰富,且非常具体,我给大家截个图看一下:

?有兴趣了解的可以直接去源码里查看。

EOF响应报文

In the MySQL client/server protocol, EOF and OK packets serve the same purpose, to mark the end of a query execution result. Due to changes in MySQL 5.7 in the OK packet (such as session state tracking), and to avoid repeating the changes in the EOF packet, the EOF packet is deprecated as of MySQL 5.7.5.

官方的大概意思就是,EOF_Packet和OK_Packet 都是用来表示一个query的结果的尾包,mysql5.7.5之后就不推荐使用EOF了,推荐使用OK包。

mysql为了和老版本客户端兼容,如果需要使用带EOF标志的OK_Packet,需要客户端连接时声明CLIENT_DEPRECATE_EOF标志。

OK_Packet和EOF_Packet区别方式和包格式如下:

  • OK: header = 0 and length of packet > 7
  • EOF: header = 0xfe and length of packet < 9

Result Set 响应报文

客户端发送查询请求后,在没有错误的情况下,服务器会返回结果集(Result Set)给客户端。

官网上称Result Set 消息是由两部分组成的

It is made up of two parts:

  • the column definitions

  • the rows

如果更细分的话,是这样描述的:

?分为五部分,结构如下:

结构说明
[Result Set Header]列数量
[Field]列信息(多个)
[EOF]列结束
[Row Data]行数据(多个)
[EOF]数据结束

--Result Set Header 结构

字节说明
1-9Field结构计数(Length Coded Binary),用于标识Field结构的数量,取值范围0x00-0xFA。
1-9额外信息(Length Coded Binary),可选字段,一般情况下不应该出现。只有像SHOW COLUMNS这种语句的执行结果才会用到额外信息(标识表格的列数量)。

--column definitions?结构?

元数据部分以字段计数的数据包开头,后跟字段定义的数据包,每个字段一个数据包,如果未设置CLIENT_DEPRECATE_EOF,则以EOF_Packet结束。

在Result Set中,Field会连续出现多次,次数由Result Set Header结构中的IField结构计数值决定。每个field就是一个列的信息。

字节说明
n目录名称(Length Coded String),在4.1及之后的版本中,该字段值为"def"。
n数据库名称(Length Coded String),数据库名称标识。
n数据表名称(Length Coded String)数据表的别名(AS之后的名称)。
n数据表原始名称(Length Coded String),AS之前的名称。
n列(字段)名称(Length Coded String),列(字段)的别名(AS之后的名称)。
4列(字段)原始名称(Length Coded String),列(字段)的原始名称(AS之前的名称)。
1填充值
2字符编码,列(字段)的字符编码值。
4列(字段)长度,列(字段)的长度值,真实长度可能小于该值,例如VARCHAR(2)类型的字段实际只能存储1个字符。
1列(字段)类型,列(字段)的类型值,取值范围参考源代码/include/mysql_com.h头文件中的enum_field_type枚举类型定义,其实就是该列的真实类型
2列(字段)标志,参考源代码/include/mysql_com.h头文件中的宏定义),这里标志着列的标志,比如如果为自增列,那么就会是AUTO_INCREMENT_FLAG
1整型值精度,该字段对DECIMALNUMERIC类型的数值字段有效,用于标识数值的精度(小数点位置)。
2填充值(0x00)
n默认值(Length Coded String),该字段用在数据表定义中,普通的查询结果中不会出现。

mysql支持的列类型如下:

类型值名称
0x00FIELD_TYPE_DECIMAL
0x01FIELD_TYPE_TINY
0x02FIELD_TYPE_SHORT
0x03FIELD_TYPE_LONG
0x04FIELD_TYPE_FLOAT
0x05FIELD_TYPE_DOUBLE
0x06FIELD_TYPE_NULL
0x07FIELD_TYPE_TIMESTAMP
0x08FIELD_TYPE_LONGLONG
0x09FIELD_TYPE_INT24
0x0AFIELD_TYPE_DATE
0x0BFIELD_TYPE_TIME
0x0CFIELD_TYPE_DATETIME
0x0DFIELD_TYPE_YEAR
0x0EFIELD_TYPE_NEWDATE
0x0FFIELD_TYPE_VARCHAR (new in MySQL 5.0)
0x10FIELD_TYPE_BIT (new in MySQL 5.0)
0xF6FIELD_TYPE_NEWDECIMAL (new in MYSQL 5.0)
0xF7FIELD_TYPE_ENUM
0xF8FIELD_TYPE_SET
0xF9FIELD_TYPE_TINY_BLOB
0xFAFIELD_TYPE_MEDIUM_BLOB
0xFBFIELD_TYPE_LONG_BLOB
0xFCFIELD_TYPE_BLOB
0xFDFIELD_TYPE_VAR_STRING
0xFEFIELD_TYPE_STRING
0xFFFIELD_TYPE_GEOMETRY

mysql支持的列的标志如下:

标志位名称
0x0001NOT_NULL_FLAG
0x0002PRI_KEY_FLAG
0x0004UNIQUE_KEY_FLAG
0x0008MULTIPLE_KEY_FLAG
0x0010BLOB_FLAG
0x0020UNSIGNED_FLAG
0x0040ZEROFILL_FLAG
0x0080BINARY_FLAG
0x0100ENUM_FLAG
0x0200AUTO_INCREMENT_FLAG
0x0400TIMESTAMP_FLAG
0x0800SET_FLAG

--Row Data 结构 / 二进制Row Data 结构

每个Row Data其实就是一行数据,包含有多个字段值,每个字段值就是一个基本的数据类型。

A row with the data for each column.

而一个Result Set消息中,会包含多个Row Data结构。

如果不是二进制的RowData结构,那么结构如下:

字节说明
n字段值(Length Coded String),行数据中的字段值,字符串形式。
...

(一行数据中包含多个字段值)

?

?如果是二进制的RowData结构,那么结构如下:

字节说明
1结构头(0x00)
(列数量 + 7 + 2) / 8空位图,前2个比特位被保留,值分别为0和1,以保证不会和OK、Error包的首字节冲突。在MySQL 5.0及之后的版本中,这2个比特位的值都为0。
n字段值,行数据中的字段值,二进制形式。
...(一行数据中包含多个字段值)

LOCAL INFILE 响应报文

如果客户端发送LOAD DATA LOCAL INFILE....命令来导入数据,就将触发该协议包,需要客户端返回LOCAL INFILE Data进行响应,直到最后客户端返回一个空包为止,整个流程见下图:

?

参考

MySQL :: MySQL Internals Manual :: 14.1 Overview

MySQL :: MySQL Internals Manual :: 14.6.4.1 COM_QUERY Response

MySQL :: MySQL Internals Manual :: 14.6.4.1 COM_QUERY Response?

MySQL协议分析 - davygeek - 博客园

mysql交互协议解析——mysql包基础数据、mysql包基本格式 - 我没货,只剩下水了 - 博客园

彻底弄懂mysql(一)--mysql的通信协议_LYue123的博客-CSDN博客_mysql通信协议

怒肝两个月MySQL源码,总结出这篇2W字的MySQL协议详解 - 21ic电子网

mysql通信协议 -- 语句执行 - 简书

MySQL 通信协议 - 程序员大本营

mysql通信协议 -- 连接创建 - 简书

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:28:13  更:2022-04-09 18:29:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:05:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码