本文整理自网络,侵删。
1.Mysql的连接方式
要了解Mysql的通讯协议,首先需要知道是以哪种连接方式去连接Mysql服务器的;Mysql的主要连接方式包括:Unix套接字,内存共享,命名管道,TCP/IP套接字等。
1.1Unix套接字
在Linux和Unix环境下,可以使用Unix套接字进行Mysql服务器的连接;Unix套接字其实不是一个网络协议,只能在客户端和Mysql服务器在同一台电脑上才可以使用,使用方式也很简单:
root@root ~]# mysql -uroot -proot mysql> show variables like 'socket'; +---------------+---------------------------+ | Variable_name | Value | +---------------+---------------------------+ | socket | /var/lib/mysql/mysql.sock | +---------------+---------------------------+ 1 row in set (0.00 sec)
以上命令查询Unix套接字文件的位置;
1.2命名管道和内存共享
在window系统中客户端和Mysql服务器在同一台电脑上,可以使用命名管道和共享内存的方式,
命名管道开启:–shared-memory=on/off;
共享内存开启:–enable-named-pipe=on/off;
1.3TCP/IP套接字
在任何系统下都可以使用的方式,也是使用最多的连接方式,本文要介绍的通讯协议也是基于此连接方式的,下面通过tcpdump对TCP/IP套接字有一个初步的了解:
服务器端:
[root@root ~]# tcpdump port 3306 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
服务器端监听3306端口(也就是Mysql的端口);
客户端:
C:\Users\hui.zhao>mysql -h64.xxx.xxx.xxx -uroot -proot mysql> exit Bye
客户端连接服务器,然后断开连接,这时候观察服务器的监听结果日志:
[root@root ~]# tcpdump port 3306 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes 02:06:25.442472 IP 153.3.251.202.33876 > root.mysql: Flags [S], seq 27289263, win 8192, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0 02:06:25.442763 IP root.mysql > 153.3.251.202.33876: Flags [S.], seq 2014324548, ack 27289264, win 14600, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0 02:06:25.617449 IP 153.3.251.202.33876 > root.mysql: Flags [.], ack 1, win 256, length 0 02:06:29.812946 IP root.mysql > 153.3.251.202.33876: Flags [P.], seq 1:57, ack 1, win 115, length 56 02:06:29.992362 IP 153.3.251.202.33876 > root.mysql: Flags [P.], seq 1:63, ack 57, win 256, length 62 02:06:29.992411 IP root.mysql > 153.3.251.202.33876: Flags [.], ack 63, win 115, length 0 02:06:29.992474 IP root.mysql > 153.3.251.202.33876: Flags [P.], seq 57:68, ack 63, win 115, length 11 02:06:30.166992 IP 153.3.251.202.33876 > root.mysql: Flags [P.], seq 63:100, ack 68, win 256, length 37 02:06:30.167109 IP root.mysql > 153.3.251.202.33876: Flags [P.], seq 68:158, ack 100, win 115, length 90 02:06:30.536298 IP 153.3.251.202.33876 > root.mysql: Flags [.], ack 158, win 256, length 0 02:06:34.568611 IP 153.3.251.202.33876 > root.mysql: Flags [P.], seq 100:105, ack 158, win 256, length 5 02:06:34.568620 IP 153.3.251.202.33876 > root.mysql: Flags [F.], seq 105, ack 158, win 256, length 0 02:06:34.568751 IP root.mysql > 153.3.251.202.33876: Flags [F.], seq 158, ack 106, win 115, length 0 02:06:34.743815 IP 153.3.251.202.33876 > root.mysql: Flags [.], ack 159, win 256, length 0
[S]:SYN发起连接标志,[P]:PUSH传送数据标志,[F]:FIN关闭连接标志,[.]:表示确认包;
可以大致看出流程:建立tcp连接,客户端和Mysql服务器建立连接通讯,关闭tcp连接;
[S][S.][.]这几个数据包表示tcp连接的三次握手;
[F.][F.][.]这几个数据包表示tcp连接的四次挥手;
中间的多个[P.][.]其实就是客户端和Mysql服务器建立连接发送的协议数据包。
2.协议分析
Mysql协议被用在Mysql Clients和Mysql Server通讯的时候,具体有以下几个场景:客户端和服务器进行连接,Mysql代理以及主从备份;
MySQL客户端与服务器的交互主要分为两个阶段:Connection Phase(连接阶段或者叫认证阶段)和Command Phase(命令阶段);
结合tcpdump的输出,客户端和服务器端通讯的整个流程大致如下:
1.建立tcp连接三次握手; 2.与Mysql服务器建立连接,即Connection Phase(连接阶段或者叫认证阶段); s->c:发送握手初始化包(a Initial Handshake Packet) c->s:发送验证包(authentication response) s->c:服务器发送认证结果包 3.认证通过之后,服务器端接受客户端的命令包,发送相应的响应包,即Command Phase(命令阶段); 4.断开连接请求exit命令; 5.四次挥手tcp断开连接;
2.1基本类型
在整个协议中的基本类型:整数型和字符串型;
2.1.1整数型
分为两种类型Fixed-Length Integer Types和Length-Encoded Integer Type;
Fixed-Length Integer Types:
一个固定长度的无符号整数将其值存储在一系列字节中,具体固定字节数可以是:1,2,3,4,6,8;
Length-Encoded Integer Type:
存储需要的字节数取决于数值的大小,具体可参照如下:
1个字节:0<=X<251;
2个字节:251<=X<2^16;
3个字节:2^16<=X<2^24;
9个字节:2^24<=X<2^64;
2.1.2字符串型
分为5种类型包括,FixedLengthString,NullTerminatedString,VariableLengthString,LengthEncodedString和RestOfPacketString;
FixedLengthString:固定长度的字符串具有已知的硬编码长度,一个例子是ERR_Packet的SQL状态,它总是5个字节长;
NullTerminatedString:以遇到Null(字节为00)结束的字符串;
VariableLengthString:可变字符串,字符串的长度由另一个字段决定或在运行时计算,比如int+value,int为长度,value为指定长度的字节数;
LengthEncodedString:以描述字符串长度的长度编码的整数作为前缀的字符串,是VariableLengthString指定的int+value方式;
RestOfPacketString:如果一个字符串是数据包的最后一个组件,它的长度可以从整个数据包长度减去当前位置来计算;
2.2基本数据包
如果MySQL客户端或服务器想要发送数据,则:
每个数据包大小不能超过2^24字节(16MB);
在每个数据块前面加上一个数据包头;
包格式如下:
int<3>:具体包内容的长度;除去int<3>+int<1>=4字节长度; int<1>:sequence_id随每个数据包递增,并可能环绕。 它从0开始,在命令阶段开始一个新的命令时重置为0; string<var>:具体数据内容,也是int<3>指定的长度;
例如:
01 00 00对应int表示具体数据内容的长度为1个字节;
00对应int表示sequence_id;
01对应string前面指定的数据内容为1个字节。
2.3报文类型
可以分成三个大类:登录认证报文,客户端请求报文以及服务器端返回报,基于mysql5.1.73(mysql4.1以后的版本)
2.3.1登录认证报文
主要在交互的认证阶段,由上文中可以知道一共分为三个阶段:Handshake Packet,authentication response以及结果包,这里主要分析前两个包;
2.3.1.1 Handshake Packet
1字节:协议版本号 NullTerminatedString:数据库版本信息 4字节:连接MySQL Server启动的线程ID 8字节:挑战随机数,用于数据库认证 1字节:填充值(0x00) 2字节:用于与客户端协商通讯方式 1字节:数据库的编码 2字节:服务器状态 13字节:预留字节 12字节:挑战随机数,用于数据库认证 1字节:填充值(0x00)
使用tcpdump进行监听,输出十六进制日志如下:
[root@root ~]# tcpdump port 3306 -X ...... 03:20:34.299521 IP root.mysql > 153.3.251.202.44658: Flags [P.], seq 1:57, ack 1, win 115, length 56 0x0000: 4508 0060 09f1 4000 4006 c666 43da 9190 E..`..@.@..fC... 0x0010: 9903 fbca 0cea ae72 bb4e 25ba 21e7 27e3 .......r.N%.!.'. 0x0020: 5018 0073 b1e0 0000 3400 0000 0a35 2e31 P..s....4....5.1 0x0030: 2e37 3300 4024 0000 5157 4222 252f 5f6f .73.@$..QWB"%/_o 0x0040: 00ff f708 0200 0000 0000 0000 0000 0000 ................ 0x0050: 0000 0032 4a5d 7553 7e45 784f 627e 7400 ...2J]uS~ExOb~t.
包的总长度是56,减去int<3>+int<1>4字节=52字节,对应的十六进制就是34;int<3>十六进制为3400 00表示包内容长度,int<1>十六进制为00表示sequence_id;后续的内容就是包体内容共52字节,0a对应的十进制是10,所有协议号版本是10;后续的数据库版本信息遇到00结束,35 2e31 2e37 33对应的5.1.73,正是当前使用的数据库版本;4024 0000对应十进制是6436;08表示数据库的编码;0200表示服务器状态;后续的13对00为预留字节;最后的13个字节是挑战随机数和填充值。
相关阅读 >>
更多相关阅读请进入《mysql》频道 >>
数据库系统概念 第6版
本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。