Mysql通讯协议的示例分析
小编给大家分享一下Mysql通讯协议的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
1.Mysql的连接方式
要了解Mysql的通讯协议,首先需要知道是以哪种连接方式去连接Mysql服务器的;Mysql的主要连接方式包括:Unix套接字,内存共享,命名管道,TCP/IP套接字等。
1.1Unix套接字
在Linux和Unix环境下,可以使用Unix套接字进行Mysql服务器的连接;Unix套接字其实不是一个网络协议,只能在客户端和Mysql服务器在同一台电脑上才可以使用,使用方式也很简单:
root@root~]#mysql-uroot-prootmysql>showvariableslike'socket';+---------------+---------------------------+|Variable_name|Value|+---------------+---------------------------+|socket|/var/lib/mysql/mysql.sock|+---------------+---------------------------+1rowinset(0.00sec)
以上命令查询Unix套接字文件的位置;
1.2命名管道和内存共享
在window系统中客户端和Mysql服务器在同一台电脑上,可以使用命名管道和共享内存的方式,
命名管道开启:–shared-memory=on/off;
共享内存开启:–enable-named-pipe=on/off;
1.3TCP/IP套接字
在任何系统下都可以使用的方式,也是使用最多的连接方式,本文要介绍的通讯协议也是基于此连接方式的,下面通过tcpdump对TCP/IP套接字有一个初步的了解:
服务器端:
[root@root~]#tcpdumpport3306tcpdump:verboseoutputsuppressed,use-vor-vvforfullprotocoldecodelisteningonvenet0,link-typeLINUX_SLL(Linuxcooked),capturesize65535bytes
服务器端监听3306端口(也就是Mysql的端口);
客户端:
C:\Users\hui.zhao>mysql-h74.xxx.xxx.xxx-uroot-prootmysql>exitBye
客户端连接服务器,然后断开连接,这时候观察服务器的监听结果日志:
[root@root~]#tcpdumpport3306tcpdump:verboseoutputsuppressed,use-vor-vvforfullprotocoldecodelisteningonvenet0,link-typeLINUX_SLL(Linuxcooked),capturesize65535bytes02:06:25.442472IP153.3.251.202.33876>root.mysql:Flags[S],seq27289263,win8192,options[mss1460,nop,wscale8,nop,nop,sackOK],length002:06:25.442763IProot.mysql>153.3.251.202.33876:Flags[S.],seq2014324548,ack27289264,win14600,options[mss1460,nop,nop,sackOK,nop,wscale7],length002:06:25.617449IP153.3.251.202.33876>root.mysql:Flags[.],ack1,win256,length002:06:29.812946IProot.mysql>153.3.251.202.33876:Flags[P.],seq1:57,ack1,win115,length5602:06:29.992362IP153.3.251.202.33876>root.mysql:Flags[P.],seq1:63,ack57,win256,length6202:06:29.992411IProot.mysql>153.3.251.202.33876:Flags[.],ack63,win115,length002:06:29.992474IProot.mysql>153.3.251.202.33876:Flags[P.],seq57:68,ack63,win115,length1102:06:30.166992IP153.3.251.202.33876>root.mysql:Flags[P.],seq63:100,ack68,win256,length3702:06:30.167109IProot.mysql>153.3.251.202.33876:Flags[P.],seq68:158,ack100,win115,length9002:06:30.536298IP153.3.251.202.33876>root.mysql:Flags[.],ack158,win256,length002:06:34.568611IP153.3.251.202.33876>root.mysql:Flags[P.],seq100:105,ack158,win256,length502:06:34.568620IP153.3.251.202.33876>root.mysql:Flags[F.],seq105,ack158,win256,length002:06:34.568751IProot.mysql>153.3.251.202.33876:Flags[F.],seq158,ack106,win115,length002:06:34.743815IP153.3.251.202.33876>root.mysql:Flags[.],ack159,win256,length0
[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服务器建立连接,即ConnectionPhase(连接阶段或者叫认证阶段);s->c:发送握手初始化包(aInitialHandshakePacket)c->s:发送验证包(authenticationresponse)s->c:服务器发送认证结果包3.认证通过之后,服务器端接受客户端的命令包,发送相应的响应包,即CommandPhase(命令阶段);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字节:连接MySQLServer启动的线程ID8字节:挑战随机数,用于数据库认证1字节:填充值(0x00)2字节:用于与客户端协商通讯方式1字节:数据库的编码2字节:服务器状态13字节:预留字节12字节:挑战随机数,用于数据库认证1字节:填充值(0x00)
使用tcpdump进行监听,输出十六进制日志如下:
[root@root~]#tcpdumpport3306-X......03:20:34.299521IProot.mysql>153.3.251.202.44658:Flags[P.],seq1:57,ack1,win115,length560x0000:4508006009f140004006c66643da9190E..`..@.@..fC...0x0010:9903fbca0ceaae72bb4e25ba21e727e3.......r.N%.!.'.0x0020:50180073b1e00000340000000a352e31P..s....4....5.10x0030:2e3733004024000051574222252f5f6f.73.@$..QWB"%/_o0x0040:00fff708020000000000000000000000................0x0050:000000324a5d75537e45784f627e7400...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个字节是挑战随机数和填充值。
2.3.1.2 Authentication Packet
4字节:用于与客户端协商通讯方式4字节:客户端发送请求报文时所支持的最大消息长度值1字节:标识通讯过程中使用的字符编码23字节:保留字节NullTerminatedString:用户名LengthEncodedString:加密后的密码NullTerminatedString:数据库名称(可选)
使用tcpdump进行监听,输出十六进制日志如下:
03:20:34.587416IP153.3.251.202.44658>root.mysql:Flags[P.],seq1:63,ack57,win256,length620x0000:4500006629ee40007006766b9903fbcaE..f).@.p.vk....0x0010:43da9190ae720cea21e727e3bb4e25f2C....r..!.'..N%.0x0020:50180100d8d200003a00000185a60f00P.......:.......0x0030:00000001210000000000000000000000....!...........0x0040:000000000000000000000000726f6f74............root0x0050:0014ff584bd2794691a0a233f2c128af...XK.yF...3..(.0x0060:d5780762c2e8.x.b..
包的总长度是62,减去int<3>+int<1>4字节=58字节,对应的十六进制就是3a;int<3>十六进制为3a00 00表示包内容长度;int<1>十六进制为01表示sequence_id;726f 6f74 00是用户名解码后是root;后面是加密后的密码类型是
LengthEncodedString,14对应的十进制是20,后面20个字节就是加密后的密码;可选的数据库名称不存在。
2.4客户端请求报文
int<1>:执行的命令,比如切换数据库string<var>:命令相应的参数
命令列表:
0x00COM_SLEEP(内部线程状态)0x01COM_QUIT关闭连接0x02COM_INIT_DB切换数据库0x03COM_QUERYSQL查询请求0x04COM_FIELD_LIST获取数据表字段信息0x05COM_CREATE_DB创建数据库0x06COM_DROP_DB删除数据库0x07COM_REFRESH清除缓存0x08COM_SHUTDOWN停止服务器0x09COM_STATISTICS获取服务器统计信息0x0ACOM_PROCESS_INFO获取当前连接的列表0x0BCOM_CONNECT(内部线程状态)0x0CCOM_PROCESS_KILL中断某个连接0x0DCOM_DEBUG保存服务器调试信息0x0ECOM_PING测试连通性0x0FCOM_TIME(内部线程状态)0x10COM_DELAYED_INSERT(内部线程状态)0x11COM_CHANGE_USER重新登陆(不断连接)0x12COM_BINLOG_DUMP获取二进制日志信息0x13COM_TABLE_DUMP获取数据表结构信息0x14COM_CONNECT_OUT(内部线程状态)0x15COM_REGISTER_SLAVE从服务器向主服务器进行注册0x16COM_STMT_PREPARE预处理SQL语句0x17COM_STMT_EXECUTE执行预处理语句0x18COM_STMT_SEND_LONG_DATA发送BLOB类型的数据0x19COM_STMT_CLOSE销毁预处理语句0x1ACOM_STMT_RESET清除预处理语句参数缓存0x1BCOM_SET_OPTION设置语句选项0x1CCOM_STMT_FETCH获取预处理语句的执行结果
比如:use test;使用tcpdump进行监听,输出十六进制日志如下:
22:04:29.379165IP153.3.251.202.33826>root.mysql:Flags[P.],seq122:131,ack222,win64019,length90x0000:450000313f194000700661759903fbcaE..1?.@.p.au....0x0010:43da919084220cea42e2524b7e1825c1C...."..B.RK~.%.0x0020:5018fa13a07b00000500000002746573P....{.......tes0x0030:74
包的总长度是9,减去int<3>+int<1>4字节=5字节,对应的十六进制就是05;int<3>十六进制为0500 00表示包内容长度;int<1>十六进制为00表示sequence_id;02对应COM_INIT_DB,后面是test的二进制编码;
2.5服务器响应报文
对于客户端发送给服务器的大多数命令,服务器返回其中一个响应的数据包:OK_Packet,ERR_Packet和EOF_Packet,Result Set;
2.5.1OK_Packet
表示成功完成一个命令,具体格式如下:
int<1>:0x00或0xFEOK包头int<lenenc>:受影响行数int<lenenc>:最后插入的索引IDint<2>:服务器状态int<2>:告警计数注:MySQL4.1及之后的版本才有string<lenenc>:服务器消息(可选)
use test;服务器返回的包,使用tcpdump进行监听,输出十六进制日志如下:
22:04:29.379308IProot.mysql>153.3.251.202.33826:Flags[P.],seq222:233,ack131,win14600,length110x0000:450800334a0a40004006867a43da9190E..3J.@.@..zC...0x0010:9903fbca0cea84227e1825c142e25254......."~.%.B.RT0x0020:501839083b6100000700000100000002P.9.;a..........0x0030:000000
包的总长度是11,减去int<3>+int<1>4字节=7字节,对应的十六进制就是07;int<3>十六进制为0700 00表示包内容长度;int<1>十六进制为01表示sequence_id;00表示包头;00表示受影响行数;00表示最后插入的索引ID;0200表示服务器状态;
2.5.2ERR_Packet
表示发生了错误,具体格式如下:
int<1>:0xFFERR包头int<2>:错误码string[1]:Sql状态标识注:MySQL4.1及之后的版本才有string[5]:Sql状态注:MySQL4.1及之后的版本才有string<EOF>:错误消息
2.5.3EOF_Packet
以标记查询执行结果的结束:
int<1>:EOF值(0xFE)int<2>:告警计数注:MySQL4.1及之后的版本才有int<2>:状态标志位注:MySQL4.1及之后的版本才有
2.5.4Result Set
当客户端发送查询请求后,在没有错误的情况下,服务器会返回结果集(Result Set)给客户端,一共有5个部分:
ResultSetHeader返回数据的列数量Field返回数据的列信息(多个)EOF列结束RowData行数据(多个)EOF数据结束
2.5.4.1Result Set Header
Length-EncodedIntegerField结构的数量Length-EncodedInteger额外信息
2.5.4.2Field
LengthEncodedString目录名称LengthEncodedString数据库名称LengthEncodedString数据表名称LengthEncodedString数据表原始名称LengthEncodedString列(字段)名称LengthEncodedString列(字段)原始名称int<1>填充值int<2>字符编码int<4>列(字段)长度int<1>列(字段)类型int<2>列(字段)标志int<1>整型值精度int<2>填充值(0x00)LengthEncodedString默认值
2.5.4.3EOF
参考2.5.3EOF_Packet
2.5.4.4Row Data
LengthEncodedString字段值......多个字段值
实例分析,表信息如下:
CREATETABLE`btest`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`age`int(11)DEFAULTNULL,`name`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=1000DEFAULTCHARSET=utf8
select * from btest;服务器返回的数据如下:
mysql>select*frombtest;+----+------+---------+|id|age|name|+----+------+---------+|1|10|zhaohui||2|11|zhaohui|+----+------+---------+
服务器返回的包,使用tcpdump进行监听,输出十六进制日志如下:
01:54:21.522660IProot.mysql>153.3.251.202.58587:Flags[P.],seq1:196,ack24,win115,length1950x0000:450800eb883940004006479343da9190E....9@.@.G.C...0x0010:9903fbca0ceae4db9dd80216eda6f730...............00x0020:50180073ca3400000100000103280000P..s.4.......(..0x0030:02036465660474657374056274657374..def.test.btest0x0040:0562746573740269640269640c3f0014.btest.id.id.?..0x0050:0000000803420000002a000003036465.....B...*....de0x0060:66047465737405627465737405627465f.test.btest.bte0x0070:737403616765036167650c3f000b0000st.age.age.?....0x0080:000300000000002c0000040364656604.......,....def.0x0090:74657374056274657374056274657374test.btest.btest0x00a0:046e616d65046e616d650c2100fd0200.name.name.!....0x00b0:00fd000000000005000005fe00002200..............".0x00c0:0d0000060131023130077a68616f6875.....1.10.zhaohu0x00d0:690d0000070132023131077a68616f68i.....2.11.zhaoh0x00e0:756905000008fe00002200ui.......".
0328 0000 02对应的是Result Set Header,03表示3个字段;03 6465 66对应的是目录名称的默认值def,03表示后面的字节数为3;04 7465 7374
对应的是数据库名称test;0562 7465 7374对应的是数据表名称btest;0562 7465 7374对应的是数据表原始名称btest;0269 64对应字段名称id;02 6964对应列(字段)原始名称id;0c3f 00对应的是填充值和字符编码;14 0000 00对应的十进制是20表示列(字段)长度;08 0342 00分别表示列(字段)类型,标识,整型值精度;00002个字节为填充值;00为默认值表示空的;
后续的age和name字段同上,不在重复;
0131类型LengthEncodedString对应的字符1就是id的值;0231 30类型LengthEncodedString对应的字符10就是age的值;07 7a68 616f 6875 69类型LengthEncodedString对应的字符zhaohui就是name的值;
以上是“Mysql通讯协议的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。