承接前文《自動反射訊息類型的 Google Protobuf 網路傳輸方案》,本文說明如何將打包方案與 muduo::net::Buffer 結合,實作 ProtobufCodec 與 ProtobufDispatcher。
Protobuf 設計經深思熟慮,預設序列化格式不含長度與類型資訊,因為在許多場景下由外部系統提供:
僅在 TCP 長連接且單連接傳遞多種訊息 時(如同時傳送 Heartbeat 與業務訊息),才需要自訂打包格式與分發器。
Codec 位於 TcpConnection 與業務邏輯之間,負責:
LengthHeaderCodec 為簡單範例(4 位元組長度前綴 + 字串)。ProtobufCodec 類似,但處理 protobuf::Message。
依序打包:長度、類型名長度、類型名、Protobuf 資料、Adler32 校驗碼。最後回填長度欄位。
shared_ptr 自動管理 protobuf::MessageErrorCallback,預設斷開連接讓客戶重試目前實作未充分利用 ZeroCopyInputStream/OutputStream,改用位元組陣列解析,留有優化空間。muduo::net::Buffer 內部使用 vector,為通用網路庫設計,未為 Protobuf 專門優化。
TCP 長連接傳遞多種 Protobuf 訊息時,需按類型分發給不同處理函數(如 Logon → onLogon,Query → onQuery)。
以 Descriptor* 為 key 的 map 註冊回呼,收到訊息查找分發。缺點:使用者需自行 down_cast 至具體類型。
結合多態與模板技巧,利用模板化派生類 CallbackT 保存類型資訊,自動完成 down_cast:
// 註冊時自動推導具體類型
dispatcher_.registerMessageCallback(
boost::bind(&QueryServer::onQuery, this, _1, _2, _3));
dispatcher_.registerMessageCallback(
boost::bind(&QueryServer::onAnswer, this, _1, _2, _3));
產生 CallbackT<Query>、CallbackT<Answer> 實體,分發時自動轉型。設計參考 shared_ptr 的 deleter 機制。
TcpConnection → ProtobufCodec → ProtobufDispatcher → 業務處理函數。四層透過回呼函數串聯,無基類、無虛函數、不侵入式,作為工具類直接作為資料成員使用。
Client/Server 範例程式碼:
下一篇將介紹利用 Protobuf 跨語言特性,以 Java 為 C++ 服務編寫自動回歸測試。