一、什么是pb協議?
ProtoBuff是一種將結構化數據進行序列化和反序列化的方法。它的作用類似XML,它的優勢主要體現在序列化后的數據小以及數據解析速度快。
適用於對數據序列化后體積以及速度要求嚴格的場景,如在即時通信領域,移動端與服務器的交互比桌面端與服務器的交互更適合使用pb協議。
二、pb與其他序列化機制對比
同為序列化機制,pb相比於更加常見的用戶數據交互的XML 、json各自有啥特點呢?
1、json: 是一種輕量級的數據交換格式。使用鍵值對的方式對數據進行封裝。使用簡單,可讀性較高,但不能表達復雜數據類型。一般的web項目中,最流行的主要還是json。因為瀏覽器對於json數據支持非常好,有很多內建的函數支持。
2、xml: 使用閉合標簽對數據進行封裝。在webservice中應用最為廣泛,但是相比於json,它的數據更加冗余,因為需要成對的閉合標簽。json使用了鍵值對的方式,不僅壓縮了一定的數據空間,同時也具有可讀性。
3、protobuf:是后起之秀,是谷歌開源的一種數據格式,適合高性能,對響應速度有要求的數據傳輸場景。因為profobuf是二進制數據格式,需要編碼和解碼,編碼和解碼雙方必須有共同的proto文件。數據本身不具有可讀性。因此只能反序列化之后得到真正可讀的數據。
---------------------
以上參考:https://blog.csdn.net/u014043213/article/details/80336805
如果已經決定使用pb,那么pb該怎么用呢?
三、怎么使用pb?
序列化基本步驟:
定義proto文件 --> 編譯proto文件 --> 導入編譯后文件 --> 對消息中各個字段復制 -->序列化(即, 調用SeriotoString()得到二進制字符串)
反序列化基本步驟:
獲取與序列化過程一致的proto文件 -->
下面以python語言下的序列化過程為例介紹:
1、按照pb格式要求編寫proto文件;
一個簡單的message格式:
Message 消息名{ 字段規則 字段類型 字段名 = 分配標識號; } 字段規則:required(必須設置) 、 optional(可以有0或1個) 、repeated(可以有0或多個) 字段類型:可以是標准類型、枚舉類型、自定義message類型 分配標識名:1、2、3……
2、使用pb編譯器對proto文件進行編譯:
protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/你的.proto文件名
需要指定源目錄(應用程序源碼目錄——如果不提供這個目錄,默認就是當前目錄),目標目錄(你的應用程序編譯后生成的代碼的目錄;通常用$SRC_DIR), 還有.proto文件的目錄路徑.此時對應的.py文件就會生成在指定的目標目錄中.因為我們case的編寫框架為python,我們想生成Python的類,所以用–python_out選項,也有類似的選項支持其它語言,例如生成C++的類,用–cpp_out選項
3、在項目中導入pb編譯生成的類文件:
4、創建類對象,並為對象的對各個字段進行賦值
5、調用SerializeToString()方法進行序列化。
---------------------
參考:
https://developers.google.cn/protocol-buffers/docs/overview
https://www.sohu.com/a/168549441_216613
https://www.cnblogs.com/tohxyblog/p/8974763.html
https://www.jianshu.com/p/2265f56805fa
四、使用pb中的坑
1、pb在進行編碼和解碼時必須使用相同的.proto文件,之前一次工作中,僅僅更新了編碼端的協議文件,服務器上文件未更新,總是出錯,又是重新編譯,又是反復看在編碼端編譯出來的類文件 ,折騰了好久,最后才意識到是兩邊的文件不一致,導致無法正常解析。其實這也體現了pb文件在使用過程中的一個缺點。普通序列化方式,只要在服務器端打出日志,傳輸的字段有沒有錯誤就很顯而易見,但是由於pb序列化的數據都是二進制格式的,日志打印出來都是亂碼,如果真的遇到業務錯誤,也不太直接看出來是傳輸字段有錯誤還是其他哪里的錯誤。不過,一般情況下嚴格按照步驟使用,出錯倒是不多。
2、repeated修飾符修飾的字段在使用時候的有一個注意點。在工作中,遇到過一個情況是,message中某個字段的字段規則是repeated,字段類型是自定義message類型。在這種場景下,對字段進行賦值的時候,需要先對自定義類型message的字段調用add方法,初始化新實例;然后對新實例中的每個元素進行賦值。例如:
message格式--

字段賦值過程--

Repeated修飾字段賦值注意:
對基本message類型,直接賦值;
對自定義message類型,調用add方法初始化新實例,再對實例中每個元素賦值

