MySQL 通信協議介紹

 MySQL 通信協議介紹

 

1、數據類型

瞭解MySQL協議包之前必需先知道其數據類型

 

 1.1 Integer Types 整數類型

(1)定長整型

固定長度, 小端編碼, 有下面幾種(括號內的代表所佔字節數):

int<1>

int<2>

int<3>

int<4>

int<6>

int<8>

 

(2)變長整型

可能長度爲1, 3, 4, 9 個字節, 實際長度取決於數值的大小.記爲 int<lenenc>

 

編碼過程, 記數值爲N:

1.若 N < 251, 則編碼爲單字節

2.若 251 <= N < 2^16, 則編碼爲 0xfc + 2-byte integer

3.若 2^16 <= N < 2^24, 則編碼爲 0xfd + 3-byte integer

4.若 2^24 <= N < 2^64, 則編碼爲0xfe + 8-byte integer

 

解碼過程, 先看第一個字節, 記其值爲N1,

1.若 N1 <= 0xfb, 則說明該整數就是N1

2.若 N1 = 0xfc,則說明接下來2字節也是該整數的部分, 取出加上0xfc即爲原數值

3.若 N1 = 0xfd, ...

4.若 N1 = 0xfe, ...

 

值得注意的是, 當協議包的第一個字節爲0xfe時, 應該檢查接下來是否有8個字節, 若沒有則說明該協議包可能是EOF_PACKET

 

1.2 String Types 字符串類型

 

(1)FixedLengthString

定長字符串,記爲 string<fix>

 

(2)NulTerminatedString

由NUL標識結束的字符串, NUL即0x00,記爲string<NUL>

 

(3)VariableLengthString

變長字符串, 長度由別的其它字段決定或者運行時動態計算出來的,記爲string<var>

 

(4)LengthEncodedString

長度編碼的字符串, 即其前面有個整型int<lenenc>說明接下來的字符串的長度, 起始就是VariableLengthString,記爲string<lenenc>

 

(5)RestOfPacketString

若一個字符串是一個協議包的最後一個字段, 那該字符串的長度當然就等於包長 - 當前位置,記爲string<EOF>

 

2.MySQL協議包

客戶端或服務端要發消息給對方時:

1.把消息分成若干個長度小於 2^24-1(即16 M)的消息

2.給每個消息前面加一個4字節包頭.

如下:

Type Name Description
int<3> payload_length payload字段的長度
int<1> sequence_id 序列號
string<var> payload payload包體

 

例如CMD_QUIT的整包字節序列爲:01 00 00 00 01

 

 

 1.通用響應報文

 

(1) OK_Packet

表示操作成功的報文,5.7開始用該報文替代EOF_Packet

 

 報文格式:

 

判斷時OK還是EOF規則:

OK: header = 0 and length of packet > 7

EOF: header = 0xfe and length of packet < 9

 

(2) ERR_Packet

表示操作失敗的報文. It contains a SQL state value if CLIENT_PROTOCOL_41 is enabled.

 

報文格式:

 

 (3) EOF_Packet

If CLIENT_PROTOCOL_41 is enabled, the EOF packet contains a warning count and status flags.

 EOF報文用來表示多個報文組成的一個報文簇的結束,比如當客戶端發送查詢命令到mysql server時,mysql會按順序回覆以下報文:

1.ResultSetHeaderPacket  --報文中攜帶了查詢結果包含的字段的個數N,以及其它一些信息

2.FieldPacket * N -- N個FieldPacket,每一個都表示一個字段的定義

3.EOF Packet -- 表示字段定義的所有報文已發送完畢

4.RowDataPacket * M -- 每個報文表示一行數據

5.EOF Packet -- 表示行數據報文發送完畢。

 

報文格式:


 

EOF_Packet和OK_Packet 都是用來表示一個query的結果的尾包,5.7.5版本EOF_Packet就不在使用了

 

上面的報文中涉及到的statu_flag取值及含義如下:

 

 

 

2.連接建立階段報文

 

(1) Handshake Packet(Server -> Client)

握手報文,當客戶端連接服務端時,當TCP連接建立完成後,Server會主動向Client發送一個握手協議報文,裏面攜帶了Server的相關信息和權能標識,關於權能標識(capabilities flag),具體可以去這裏

 

 

Java代碼 
  1. 1              [0a] protocol version -- 協議版本  
  2. string[NUL]    server version -- Server版本  
  3. 4              connection id  
  4. string[8]      auth-plugin-data-part-1  
  5. 1              [00] filler -- 填充,總是0x00  
  6. 2              capability flags (lower 2 bytes) --Server權能標識  
  7.   if more data in the packet:  
  8. 1              character set -- 連接所使用的字符集  
  9. 2              status flags  
  10. 2              capability flags (upper 2 bytes)  
  11.   if capabilities & CLIENT_PLUGIN_AUTH {  
  12. 1              length of auth-plugin-data  
  13.   } else {  
  14. 1              [00]  
  15.   }  
  16. string[10]     reserved (all [00])  
  17.   if capabilities & CLIENT_SECURE_CONNECTION {  
  18. string[$len]   auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))  
  19.   if capabilities & CLIENT_PLUGIN_AUTH {  
  20. string[NUL]    auth-plugin name  
  21.   }  

 

 

(2)HandShake Response Packet(Client -> Server)

客戶端收到Handshake Packet後,生成一個Response併發給Server,裏面攜帶客戶端的權能標識,用戶名等相關的信息,如果Handshake Packet中的權能標識中帶有client_protocol_41標識位,那麼客戶端將生成的Response爲HandShake Response41,否則生成的爲HandShake Response320,我們這裏就不管HandShake Response320,因爲現在的Server基本都會支持這個

 

HandShake Response41格式:

 

Java代碼 
  1. 4              capability flags, CLIENT_PROTOCOL_41 always set -- 客戶端的權能標識  
  2. 4              max-packet size -- 最大包大小  
  3. 1              character set -- 字符集  
  4. string[23]     reserved (all [0]) -- 保留,總是0  
  5. string[NUL]    username -- 用戶名  
  6.   if capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA { -- 看了mycat的源碼才知道,這個其實是密碼  
  7. lenenc-int     length of auth-response  
  8. string[n]      auth-response  
  9.   } else if capabilities & CLIENT_SECURE_CONNECTION {  
  10. 1              length of auth-response  
  11. string[n]      auth-response  
  12.   } else {  
  13. string[NUL]    auth-response  
  14.   }  
  15.   if capabilities & CLIENT_CONNECT_WITH_DB { -- 連接默認數據庫名  
  16. string[NUL]    database  
  17.   }  
  18.   if capabilities & CLIENT_PLUGIN_AUTH {  
  19. string[NUL]    auth plugin name  
  20.   }  
  21.   if capabilities & CLIENT_CONNECT_ATTRS {  
  22. lenenc-int     length of all key-values  
  23. lenenc-str     key  
  24. lenenc-str     value  
  25.    if-more data in 'length of all key-values', more keys and value pairs  
  26.   }  

 

 

3.普通請求/響應報文

在連接建立後,Client就可以發送普通的查詢或者其它命令給Server了,下面對這些命令進行介紹

 

1.COM_SLEEP 請求

這個是Server內部的命令,不是客戶端給服務端發的,忽略即可

 

Java代碼 
  1. 1              [00] COM_SLEEP  

 

 

 

2.COM_QUIT 請求

當客戶端要關閉連接時,發送該命令到Server

 

Java代碼 
  1. 1              [01] COM_QUIT  

 

返回:要麼是OK Packet,要麼就連接關閉

 

3.COM_INIT_DB 請求

修改連接默認的schema

 

Java代碼 
  1. 1              [02] COM_INIT_DB  
  2. string[EOF]    schema name -- 數據庫名  

 

返回:OK Packet 或者ERR Packet

 

4.COM_QUERY 請求

發送普通查詢請求,這個查詢是立即執行的,因此預編譯不是發這個命令的

 

Java代碼 
  1. 1              [03] COM_QUERY  
  2. string[EOF]    the query the server shall execute -- sql語句  

 

返回:COM_QUERY_RESPONSE Packet

 

5.COM_QUERY_PACKET 響應

COM_QUERY的響應報文,該報文只是個邏輯上的報文,其組成爲以下幾個中的一個:

  • ERR Packet
  • OK Packet
  • ResultSet Packet -- 普通查詢結果
  • LOAD DATA INFILE REQUEST Packet

6.ResultSetPacket 響應
普通查詢結果,也是一個邏輯上的報文,其由以下部分組成:

1.ResultSetHeaderPacket -- 只包含一個int<lenenc>的整數(記爲N,表示結果字段的個數)和一個8字節的extra附加信息

2.ColumnDefinitionPacket * N -- N個ColumnDefinitionPacket ,每個ColumnDefinitionPacket表示一個字段的信息,其格式如下:

Java代碼 
  1. lenenc_str     catalog  
  2. lenenc_str     schema  
  3. lenenc_str     table  
  4. lenenc_str     org_table  
  5. lenenc_str     name  
  6. lenenc_str     org_name  
  7. lenenc_int     length of fixed-length fields [0c]  
  8. 2              character set  
  9. 4              column length  
  10. 1              type  
  11. 2              flags  
  12. 1              decimals  
  13. 2              filler [00] [00]  
  14.   if command was COM_FIELD_LIST {  
  15. lenenc_int     length of default-values  
  16. string[$len]   default values  
  17.   }  

 3.EOF Packet 表示所有ColumnDefinitionPacket都發送完了,接下來將發行數據了 

4.任意個RowDataPacket,每一個代表一行數據,其中NULL用0xfb(251)表示,其格式如下:

Java代碼 
  1. lenenc_str        field1's value -- 第一個字段的值  
  2. lenenc_str        field2's value -- 第二個字段的值  
  3. ...  
  4. lenenc_str        fieldN's value -- 第N個字段的值  

 5.EOF Packet,表示ResultSetPacket完畢,若此包中的SERVER_MORE_RESULT_EXISTS被設置,則則說明接下來還有ResultSetPacket,又回到第一步開始接收...

 

整個查詢過程如下圖:

 

 

 

7.COM_FIELD_LIST 請求

獲取字段定義,5.7.11開始已棄用

 

Java代碼 
  1. 1              [04] COM_FIELD_LIST  
  2. string[NUL]    table -- 表名  
  3. string[EOF]    field wildcard 字段通配符  

 

返回:COM_FIELD_LIST RESPONSE Packet

 

 

8.COM_FIELD_LIST 響應

COM_FIELD_LIST的響應報文,該報文是一個邏輯報文,其組成爲以下一種:

1.ERR packet

2.任意個ColumnDefinitionPacket加一個EOFPacket

 

9.COM_CREATE_DB 請求

創建數據庫請求

 

Java代碼 
  1. 1              [05] COM_CREATE_DB  
  2. string[EOF]    schema name -- 數據庫名  

 返回:OK Packet或者ERR Packet

 

10.COM_DROP_DB 請求

刪除數據庫請求

 

Java代碼 
  1. 1              [06] COM_DROP_DB  
  2. string[EOF]    schema name -- 數據庫名  

 

返回:OK Packet 或者 ERR Packet

 

11.COM_REFRESH 請求

Flush ... 和RESET ... 語句的實現命令,從5.7.11版本開始已棄用,改用COM_QUERY,執行FLUSH語句或者

 

Java代碼 
  1. 1              [07] COM_REFRESH  
  2. 1              sub_command -- 命令,取值見下  

 sub_command取值:


 

 返回:OK Packet或者ERR Packet

 

 

12.COM_SHUTDOWN 請求

 shutdown mysql server的請求,5.7.9已棄用,8.0已移除,執行mysqladmin shutdown時發送該命令

 

Java代碼 
  1. 1              [08] COM_SHUTDOWN  
  2.   if more data {  
  3. 1              shutdown type  
  4.   }  

 

 shutdown type取值:

 

返回:OK Packet或者ERR packet

 

13.COM_STATISTICS 請求

獲取human readable的mysql server統計信息,執行mysqladmin status時發送該命令

 

 

Java代碼 
  1. 1              [09] COM_STATISTICS  

 

 

返回:string<EOF>

 

 

 14.COM_PROCESS_INFO 請求

  get a list of active threads,執行show processlist 或者 mysqladminproesslist時發送該命令

 

 

Java代碼 
  1. 1              [0a] COM_PROCCESS_INFO  

 

 

返回:ResultSetPacket 或者ERR Packet

 

15.COM_CONNECT 請求

mysql server 內部命令,5.7.11版本棄用,使用COM_QUERY替代

 

16.COM_PROCESS_KILL 請求

關閉連接

 

 

Java代碼 
  1. 1              [0c] COM_PROCCESS_KILL  
  2. 4              connection id -- 連接ID,這個是在HandShake Packet傳過來的  

 

 

返回:OK Packet或者ERR Packet

 

 

16.COM_DEBUG 請求

COM_DEBUG triggers a dump on internal debug info to stdout of the mysql-server.The SUPER privilege is required for this operation.執行mysqladmin debug時發送該命令

 

 

Java代碼 
  1. 1              [0d] COM_DEBUG  

 

 

返回:EOF Packet或者ERR Packet

 

17.COM_PING 請求

心跳檢測

 

 

Java代碼 
  1. 1              [0e] COM_PING  

 

 

返回:OK Packet

 

18.COM_TIME 

mysql server內部命令

 

19.COM_DELAYED_INSERT

mysql server內部命令

 

20.COM_CHANGE_USER 請求

更改當前連接的用戶並重置連接狀態,包括user variables、臨時表和預編譯語句等等...

 

 

Java代碼 
  1. 1              [11] COM_CHANGE_USER  
  2. string[NUL]    user  
  3.   if capabilities & SECURE_CONNECTION {  
  4. 1              auth-response-len  
  5. string[$len]   auth-response  
  6.   } else {  
  7. string[NUL]    auth-response  
  8.   }  
  9. string[NUL]    schema-name  
  10.   if more data {  
  11. 2              character-set  
  12.     if capabilities & CLIENT_PLUGIN_AUTH {  
  13. string[NUL]    auth plugin name  
  14.     }  
  15.     if capabilities & CLIENT_CONNECT_ATTRS) {  
  16. lenenc-int     length of all key-values  
  17. lenenc-str     key  
  18. lenenc-str     value  
  19.    if-more data in 'length of all key-values', more keys and value pairs  
  20.     }  
  21.   }  

 

 

 

21.COM_RESET_CONNECTION 請求

Resets the session state; more lightweight than COM_CHANGE_USER because it does not close and reopen the connection, and does not re-authenticate

 

 

Java代碼 
  1. 1              [1f] COM_RESET_CONNECTION  

 

 

返回:OK Packet或者ERR Packet

 

22.COM_DAEMON 請求

mysql server內部命令

 

23.COM_STMT_PREPARE 請求

預編譯語句,執行conn.preparedStatement(sql)時發送該命令

 

 

Java代碼 
  1. 1                  the COM_STMT_PREPARE command   
  2. string<EOF>        query statement -- sql語句  

 

 

返回:COM_STMT_PREPARED OK Packet或者Err Packet

 

24.COM_STMT_PREPARE Response 響應

預編譯成功時的響應報文,時邏輯報文,其由多個報文組成:

1.第一個報文包含預編譯成功信息,其格式如下:

 

Java代碼 
  1. 1        status, [00]=OK --成功標誌  
  2. 4        statementId -- 預編譯的語句ID  
  3. 2        number of columns -- 字段個數  
  4. 2        number of params -- 參數個數  
  5. 1        reserved, always 00 -- 保留  
  6. 2        number of warnings -- 警告個數  

 

2.如果上面的參數個數(記爲N)大於0的話,那麼接下來會有N個ColumnDefinitionPacket加上一個EOF Packet會被髮送

 

3.如果上面的字段個數(記爲M)大於0的話,那麼接下來會有M個ColumnDefinitionPacket加上一個EOF Packet會被髮送

 

 

 

25.COM_STMT_SEND_LONG_DATA請求

發送參數值給預編譯語句,預編譯中有幾個?就得發幾個該請求,並且都得在COM_STMT_EXECUTE之前發送

 

Java代碼 
  1. 1              [18] COM_STMT_SEND_LONG_DATA  
  2. 4              statement-id -- 預編譯語句ID  
  3. 2              param-id -- 參數ID  
  4. n              data -- 參數值  

 

返回:無返回

 

26.COM_STMT_EXECUTE請求

執行預編譯語句

Java代碼 
  1. 1              [17] COM_STMT_EXECUTE  
  2. 4              stmt-id -- 語句ID  
  3. 1              flags  
  4. 4              iteration-count, always 1  
  5. if num-params > 0:  
  6. n              NULL-bitmap, length: (num-params+7)/8  
  7. 1              new-params-bound-flag  
  8. if new-params-bound-flag == 1:  
  9. n              type of each parameter, length: num-params * 2  
  10. n              value of each parameter  

flags取值:

 

 

 

返回:COM_STMT_EXECUTE Response

 

27.COM_STMT_EXECUTE Response響應

 COM_STMT_EXECUTE 的響應報文,是下面三者之一:

1.OK Packet -- 執行update時

2.Err Packet

3.Binary Protocol ResultSet Packet --執行查詢時

 

Binary Protocol ResultSet 

binary protocol result和之前講的ResultSetPacket相似,

 

28.COM_STMT_CLOSE請求

 關閉預編譯語句,該請求無響應

 

Java代碼 
  1. 1              [19] COM_STMT_CLOSE  
  2. 4              statement-id -- 預編譯語句ID  

 

 

29.COM_STMT_RESET請求

 清空由COM_STMT_SEND_LONG_DATA發送的所有參數值,並關閉由COM_STMT_EXECUTE打開的CURSOR

 

Java代碼 
  1. 1              [1a] COM_STMT_RESET  
  2. 4              statement-id  

 

返回:OK Packet或者ERR Packet

 

// TODO 未完待補充

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章