1. 程式人生 > 資料庫 >詳解Mysql通訊協議

詳解Mysql通訊協議

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,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,sackOK],length 0
02:06:25.442763 IP root.mysql > 153.3.251.202.33876: Flags [S.],seq 2014324548,ack 27289264,win 14600,sackOK,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,win 115,length 56
02:06:29.992362 IP 153.3.251.202.33876 > root.mysql: Flags [P.],seq 1:63,ack 57,length 62
02:06:29.992411 IP root.mysql > 153.3.251.202.33876: Flags [.],ack 63,length 0
02:06:29.992474 IP root.mysql > 153.3.251.202.33876: Flags [P.],seq 57:68,length 11
02:06:30.166992 IP 153.3.251.202.33876 > root.mysql: Flags [P.],seq 63:100,ack 68,length 37
02:06:30.167109 IP root.mysql > 153.3.251.202.33876: Flags [P.],seq 68:158,ack 100,length 90
02:06:30.536298 IP 153.3.251.202.33876 > root.mysql: Flags [.],ack 158,length 0
02:06:34.568611 IP 153.3.251.202.33876 > root.mysql: Flags [P.],seq 100:105,length 5
02:06:34.568620 IP 153.3.251.202.33876 > root.mysql: Flags [F.],seq 105,length 0
02:06:34.568751 IP root.mysql > 153.3.251.202.33876: Flags [F.],seq 158,ack 106,length 0
02:06:34.743815 IP 153.3.251.202.33876 > root.mysql: Flags [.],ack 159,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.],length 56
 0x0000: 4508 0060 09f1 4000 4006 c666 43da 9190 E..`..@[email protected]...
 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個位元組是挑戰隨機數和填充值。

2.3.1.2 Authentication Packet

4位元組:用於與客戶端協商通訊方式
4位元組:客戶端傳送請求報文時所支援的最大訊息長度值
1位元組:標識通訊過程中使用的字元編碼
23位元組:保留位元組
NullTerminatedString:使用者名稱
LengthEncodedString:加密後的密碼
NullTerminatedString:資料庫名稱(可選)

使用tcpdump進行監聽,輸出十六進位制日誌如下:

03:20:34.587416 IP 153.3.251.202.44658 > root.mysql: Flags [P.],length 62
 0x0000: 4500 0066 29ee 4000 7006 766b 9903 fbca E..f)[email protected]....
 0x0010: 43da 9190 ae72 0cea 21e7 27e3 bb4e 25f2 C....r..!.'..N%.
 0x0020: 5018 0100 d8d2 0000 3a00 0001 85a6 0f00 P.......:.......
 0x0030: 0000 0001 2100 0000 0000 0000 0000 0000 ....!...........
 0x0040: 0000 0000 0000 0000 0000 0000 726f 6f74 ............root
 0x0050: 0014 ff58 4bd2 7946 91a0 a233 f2c1 28af ...XK.yF...3..(.
 0x0060: d578 0762 c2e8       .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>:命令相應的引數

命令列表:

0x00 COM_SLEEP (內部執行緒狀態)
0x01 COM_QUIT 關閉連線
0x02 COM_INIT_DB 切換資料庫
0x03 COM_QUERY SQL查詢請求
0x04 COM_FIELD_LIST 獲取資料表字段資訊
0x05 COM_CREATE_DB 建立資料庫
0x06 COM_DROP_DB 刪除資料庫
0x07 COM_REFRESH 清除快取
0x08 COM_SHUTDOWN 停止伺服器
0x09 COM_STATISTICS 獲取伺服器統計資訊
0x0A COM_PROCESS_INFO 獲取當前連線的列表
0x0B COM_CONNECT (內部執行緒狀態)
0x0C COM_PROCESS_KILL 中斷某個連線
0x0D COM_DEBUG 儲存伺服器除錯資訊
0x0E COM_PING 測試連通性
0x0F COM_TIME (內部執行緒狀態)
0x10 COM_DELAYED_INSERT (內部執行緒狀態)
0x11 COM_CHANGE_USER 重新登陸(不斷連線)
0x12 COM_BINLOG_DUMP 獲取二進位制日誌資訊
0x13 COM_TABLE_DUMP 獲取資料表結構資訊
0x14 COM_CONNECT_OUT (內部執行緒狀態)
0x15 COM_REGISTER_SLAVE 從伺服器向主伺服器進行註冊
0x16 COM_STMT_PREPARE 預處理SQL語句
0x17 COM_STMT_EXECUTE 執行預處理語句
0x18 COM_STMT_SEND_LONG_DATA 傳送BLOB型別的資料
0x19 COM_STMT_CLOSE 銷燬預處理語句
0x1A COM_STMT_RESET 清除預處理語句引數快取
0x1B COM_SET_OPTION 設定語句選項
0x1C COM_STMT_FETCH 獲取預處理語句的執行結果

比如:use test;使用tcpdump進行監聽,輸出十六進位制日誌如下:

22:04:29.379165 IP 153.3.251.202.33826 > root.mysql: Flags [P.],seq 122:131,ack 222,win 64019,length 9
 0x0000: 4500 0031 3f19 4000 7006 6175 9903 fbca E..1?[email protected]....
 0x0010: 43da 9190 8422 0cea 42e2 524b 7e18 25c1 C...."..B.RK~.%.
 0x0020: 5018 fa13 a07b 0000 0500 0000 0274 6573 P....{.......tes
 0x0030: 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>:最後插入的索引ID
int<2>:伺服器狀態
int<2>:告警計數 注:MySQL 4.1 及之後的版本才有
string<lenenc>:伺服器訊息(可選)

use test;伺服器返回的包,使用tcpdump進行監聽,輸出十六進位制日誌如下:

22:04:29.379308 IP root.mysql > 153.3.251.202.33826: Flags [P.],seq 222:233,ack 131,length 11
 0x0000: 4508 0033 4a0a 4000 4006 867a 43da 9190 E..3J.@[email protected]...
 0x0010: 9903 fbca 0cea 8422 7e18 25c1 42e2 5254 ......."~.%.B.RT
 0x0020: 5018 3908 3b61 0000 0700 0001 0000 0002 P.9.;a..........
 0x0030: 0000 00

包的總長度是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>:0xFF ERR包頭
int<2>:錯誤碼
string[1]:Sql狀態標識 注:MySQL 4.1 及之後的版本才有
string[5]:Sql狀態  注:MySQL 4.1 及之後的版本才有
string<EOF>:錯誤訊息

2.5.3EOF_Packet

以標記查詢執行結果的結束:

int<1>:EOF值(0xFE)
int<2>:告警計數 注:MySQL 4.1 及之後的版本才有
int<2>:狀態標誌位 注:MySQL 4.1 及之後的版本才有

2.5.4Result Set

當客戶端傳送查詢請求後,在沒有錯誤的情況下,伺服器會返回結果集(Result Set)給客戶端,一共有5個部分:

Result Set Header  返回資料的列數量
Field     返回資料的列資訊(多個)
EOF      列結束
Row Data    行資料(多個)
EOF      資料結束

2.5.4.1Result Set Header

Length-Encoded Integer Field結構的數量
Length-Encoded Integer 額外資訊

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  欄位值
......     多個欄位值

例項分析,表資訊如下:

CREATE TABLE `btest` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,`age` int(11) DEFAULT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8

select * from btest;伺服器返回的資料如下:

mysql> select * from btest;
+----+------+---------+
| id | age | name |
+----+------+---------+
| 1 | 10 | zhaohui |
| 2 | 11 | zhaohui |
+----+------+---------+

伺服器返回的包,使用tcpdump進行監聽,輸出十六進位制日誌如下:

01:54:21.522660 IP root.mysql > 153.3.251.202.58587: Flags [P.],seq 1:196,ack 24,length 195
 0x0000: 4508 00eb 8839 4000 4006 4793 43da 9190 E....9@[email protected]...
 0x0010: 9903 fbca 0cea e4db 9dd8 0216 eda6 f730 ...............0
 0x0020: 5018 0073 ca34 0000 0100 0001 0328 0000 P..s.4.......(..
 0x0030: 0203 6465 6604 7465 7374 0562 7465 7374 ..def.test.btest
 0x0040: 0562 7465 7374 0269 6402 6964 0c3f 0014 .btest.id.id.?..
 0x0050: 0000 0008 0342 0000 002a 0000 0303 6465 .....B...*....de
 0x0060: 6604 7465 7374 0562 7465 7374 0562 7465 f.test.btest.bte
 0x0070: 7374 0361 6765 0361 6765 0c3f 000b 0000 st.age.age.?....
 0x0080: 0003 0000 0000 002c 0000 0403 6465 6604 .......,....def.
 0x0090: 7465 7374 0562 7465 7374 0562 7465 7374 test.btest.btest
 0x00a0: 046e 616d 6504 6e61 6d65 0c21 00fd 0200 .name.name.!....
 0x00b0: 00fd 0000 0000 0005 0000 05fe 0000 2200 ..............".
 0x00c0: 0d00 0006 0131 0231 3007 7a68 616f 6875 .....1.10.zhaohu
 0x00d0: 690d 0000 0701 3202 3131 077a 6861 6f68 i.....2.11.zhaoh
 0x00e0: 7569 0500 0008 fe00 0022 00    ui.......".

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通訊協議相關的全部內容,大家在學習的時候如果還有任何不明白的地方可以留言給我們,感謝你對我們的支援。