MySQL原始碼分析之 通訊協議(一)
MySQL原始碼分析之 通訊協議(一)
mysql 通訊協議用於 mysql 客戶端和伺服器之間的通訊,通過以下幾種方式實現:
1)、介面: (Connector/C, Connector/J, 等) 即平時我們所說的 JDBC ODBC 等介面
2)、mysql 中介軟體
3)、主伺服器和從伺服器之間的通訊
mysql 協議支援一下幾點功能:
1)、使用 SSL 的透明加密
2)、透明壓縮
3)、連線階段,進行身份驗證和資料交換的能力
4)、執行階段,接收客戶端發來的命令並執行他們
互動過程:
MySQL客戶端與伺服器的互動主要分為兩個階段:握手認證階段和命令執行階段。
握手認證階段為客戶端與伺服器建立連線後進行,互動過程如下:
- 伺服器 -> 客戶端:握手初始化訊息
- 客戶端 -> 伺服器:登陸認證訊息
- 伺服器 -> 客戶端:認證結果訊息
客戶端認證成功後,會進入命令執行階段,互動過程如下:
- 客戶端 -> 伺服器:執行命令訊息
- 伺服器 -> 客戶端:命令執行結果
MySQL客戶端與伺服器的完整互動過程如下
基本型別:
1、整型
整型分為固定長度的整型和可變長度的整型(變長在這裡指的是儲存長度)。
固定長度型別屬於無符號整型,分別有1、2、3、4、6、8位元組長度,使用小位元組序傳輸最低有效位元組排在第一位。以3位元組長度整型為例可以檢視 int3store()
變長整型,可能佔用1、3、4、9個位元組,具體取決於其數值。把一個整型值轉換為一個可變位元組長度儲存需要如下操作:
因此,如果需要將變長儲存的整型轉化為數值,需要檢查第一個位元組。
注意: 如果資料包的第一個位元組是長度編碼的整數,其位元組值為0xFE,則必須檢查資料包的長度,以驗證其是否有足夠的空間容納8位元組整數。如果不是,它可能是一個EOF資料包。
2、字串
字串在協議中有以下幾種形勢:
1)、固定長度的字串,具有已知的硬編碼長度。例如,ERR資料包的sql狀態總是5位元組長
2)、字串長度不固定,當遇到'NULL'(0x00)字元時結束。
3)、字串的長度由另一個欄位確定,或在執行時計算
4)、長度編碼字串,字串長度不固定,無'NULL'(0x00)結束符,編碼方式與上面的 Length Coded integer 相同
5)、如果字串是資料包的最後一個組成部分,則可以從資料包的總長度減去當前位置來計算其長度。
報文結構: 如果 MySQL 客戶端和伺服器想傳送資料,需要將資料拆為2**24大小的資料包(即16M)因此客戶端和伺服器之間以最大16M 的資料包進行交換。會為每個資料塊預先新增一個數據包頭。因此可以這麼理解:報文分為訊息頭和訊息體兩部分,其中訊息頭佔用固定的4個位元組,訊息體長度由訊息頭中的長度欄位決定,報文結構如下:
1、訊息頭,記錄了報文長度:用於標記當前請求訊息的實際資料長度值,以位元組為單位,佔用3個位元組,最大值為 0xFFFFFF,即接近 16 MB 大小(比16MB少1個位元組)
2、訊息頭,序列號,在一次完整的請求/響應互動過程中,用於保證訊息順序的正確,每次客戶端發起請求時,序號值都會從0開始計算。
3、訊息體,訊息體用於存放請求的內容及響應的資料,長度由訊息頭中的長度值決定。
通用響應包(服務響應報文):
響應包可以分為三種,OK_Packet、 ERR_Packet、EOF_Packet。從MySQL 5.7.5開始,OK資料包也被用來表示EOF,EOF資料包被棄用。如果設定了CLIENT_PROTOCOL_41,即MySQL 版本大於4.1。
該資料包包含一個警告計數。
1、OK 響應報文
客戶端的命令執行正確時,伺服器會返回OK響應報文。
如果 header = 0 並且packer 長度大於7,說明這個包是 OK 資料包
如果 header = 0xFE 並且 packer 長度小於9,說明這個包是 EOF 包。
affecred rows:受影響行數,當執行 INSERT
/UPDATE
/DELETE
語句時所影響的資料行數
last_insert_id: 值為AUTO_INCREMENT
索引欄位生成,如果沒有索引欄位,則為0x00。注意:當INSERT
插入語句為多行資料時,該索引ID值為第一個插入的資料行索引值,而非最後一個
status_flags: 伺服器狀態,客戶端可以通過該值檢查命令是否在事務處理中
warnings: 告警次數,即告警發生的次數
session state info: 會話狀態資訊
info: 伺服器訊息,伺服器返回給客戶端的訊息,一般為簡單的描述性字串,可選欄位。
**會話狀態資訊**
狀態變化資訊作為一組狀態變化塊在OK資料包中傳送,這些狀態變化塊由以下部分組成:
型別:資料的型別,可以檢視 enum_session_state_type.。 資料,會話資訊改變的資料
enum enum_session_state_type { SESSION_TRACK_SYSTEM_VARIABLES, /**< Session system variables */ SESSION_TRACK_SCHEMA, /**< Current schema */ SESSION_TRACK_STATE_CHANGE, /**< track session state changes */ SESSION_TRACK_GTIDS, /**< See also: session_track_gtids */ SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /**< Transaction chistics */ SESSION_TRACK_TRANSACTION_STATE /**< Transaction state */ };
資料欄位的解釋取決於型別值。
1)、SESSION_TRACK_SYSTEM_VARIABLES 會話跟蹤系統變數
2)、SESSION_TRACK_SCHEMA 會話跟蹤模式
3)、SESSION_TRACK_STATE_CHANGE 會話跟蹤狀態更改。 指示會話狀態是否發生更改的標誌位元組。此標誌表示為ASCII值
2、ERR 響應報文
錯誤包意味著產生了錯誤資訊,在 MySQL4.1版本之後,它包含一個 SQL 狀態值,錯誤文字大小不能超過 Error texts cannot exceed。 程式碼函式 net_send_error_packet()
header: 訊息頭,ERR 報文問 0xFF
error-code: 錯誤碼,定義在原始碼/include/mysqld_error.h
標頭檔案中
sql_state_marker: 伺服器狀態標誌,恆為'#'字元
sql_sate: 伺服器狀態,伺服器將錯誤編號通過mysql_errno_to_sqlstate
函式轉換為狀態值,狀態值由5位元組的ASCII字元組成,定義在原始碼/include/sql_state.h
標頭檔案中
error_message: 錯誤資訊,錯誤訊息字串到達訊息尾時結束,長度可以由訊息頭中的長度值計算得出。訊息長度為0-512位元組
3、EOF 響應報文
如果啟用了CLIENT_PROTOCOL_41,則EOF資料包包含警告計數和狀態標誌。
在 mysql 的通訊協議中,EOF 資料包和 OK 資料包是一樣的目的,用來標記一個查詢結果的結束。在 MySQL5.7因為 OK 資料包發生了更改(如會話狀態跟蹤),為了避免 EOF 資料發生重複更改,在 MySQL5.7.5之後棄用 OK 資料包。EOF_資料包可能出現在可能出現Protocol::engthCodedInteger的地方。您必須檢查資料包長度是否小於9,以確保它是EOF_資料包。
warnings: 告警計數,伺服器告警數量,在所有資料都發送給客戶端後該值才有效。
status_flags: 狀態標誌位,包含類似SERVER_MORE_RESULTS_EXISTS
這樣的標誌位。
注:由於EOF值與其它Result Set結構共用1位元組,所以在收到報文後需要對EOF包的真實性進行校驗,校驗條件為:
- 第1位元組值為0xFE
- 包長度小於9位元組
未完待續。。。。