應用層通訊協定設計

2023-09-14 15:00:27

一、應用層通訊協定概述

TCP/UDP是基於位元組流的傳輸層通訊協定,對於其的程式設計是基於IO流程式設計,所謂「流」,就是沒有界限的一長串二進位制資料。TCP/UDP作為傳輸層協定,並不瞭解上層業務資料的具體含義,它會根據TCP緩衝區的實際情況進行封包的劃分。所以在業務上一個完整的封包在進行傳輸時,可能會被拆分成多個包進行傳送,也可能將很多小的封包封裝成一個大的封包傳送,也就是TCP/UDP的拆包和粘包問題。如果直接序列化發出封包,接收方無法知道一個完整的報文從哪裡開始,到哪裡結束,這個問題需要通過上層的應用協定設計來解決。

二、業界主流協定調研

目前業界主流的協定的解決方案如下:

1.訊息定長:報文長度固定,例如每個報文的長度固定為 200 位元組,如果不夠空位補空格,接受方每次拿 200 位元組。

2.使用特殊分隔符分隔:例如每條報文結束都新增回車換行符作為報文分隔符,接收方讀到回車換行符則分割出報文。

3.分為訊息頭和訊息體:訊息頭包含訊息的長度,接收方從訊息頭拿到訊息長度,就知道剩下的報文是多少位元組了。

4.更復雜的自定義應用層協定。

三、自定義應用層通訊協定結構

綜合以上內容,本專案工程中定義了一個應用層通訊協定,結構如下:

 

 

如上圖所示,傳送的資料由訊息頭(header)和主體(body)組成,訊息頭包括:

  1. 報文型別:不同型別的報文在伺服器中執行不同的指令和功能。
  2. 資料長度:資料長度由訊息頭長度加上資料主體內容的長度組成。

訊息主體為定長的資料緩衝區(但傳輸的訊息長度是不定的)。

為了實現上述的結構,定義了兩個結構體,分別是訊息頭結構體和訊息結構體,訊息頭結構體巢狀在訊息結構體中,同時定義了一個列舉型別,用於定義通訊所需的各種訊息型別。

 

 

 

不同型別的訊息的編碼方式如下表所示:

 


可以看到,報文整體由$分隔的單個字串組成,訊息頭的組成基本相同,以logIn為例,報文的第一位是訊息型別LogIn,第二位是不包括訊息頭的訊息長度,之後依次是使用者名稱和密碼。而在Getfrdlist中,除了訊息頭,好友人數之外,迴圈編碼了由uidunameusexrole組成的字串,各項之間用#分隔。

 

 

協定由伺服器端和使用者端雙方遵守,共用一套相同的編碼和解碼函數,編碼即是按照前一頁的協定具體內容拼接成字串。解碼需要讀取訊息頭,先判斷訊息型別,用於區分不同訊息以確定不同的解碼方式,然後獲取訊息長度,用於對報文進行長度校驗,以確保資料傳送的安全性和完整性。

 

四、總結

在我看來,通訊協定的設計主要需要滿足三個點:

  1. 統一:協定由伺服器端和使用者端雙方遵守,共用一套相同的編碼和解碼函數。
  2. 區分:用訊息頭來區分不同的訊息型別,用於判斷是什麼型別的訊息,選擇對應的解碼。
  3. 安全:要對封包的完整性進行校驗,進行長度的校驗是最基本的校驗,常見的檢驗方式由checksum校驗和、CRC校驗等型別。