首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

在 muduo 中實作 Protobuf 編解碼器與訊息分發器

     編輯:關於C++

承接前文《自動反射訊息類型的 Google Protobuf 網路傳輸方案》,本文說明如何將打包方案與 muduo::net::Buffer 結合,實作 ProtobufCodec 與 ProtobufDispatcher。

背景:為什麼 Protobuf 預設格式不含長度與類型?

Protobuf 設計經深思熟慮,預設序列化格式不含長度與類型資訊,因為在許多場景下由外部系統提供:

  • 檔案儲存:檔案名與長度提供類型與邊界
  • 資料庫:欄位名與長度提供元資訊
  • UDP 固定埠口:埠口與封包長度隱含類型與邊界
  • TCP 短連接固定埠口:埠口與位元流長度提供資訊
  • RPC 呼叫:方法名隱含 Request/Response 類型

僅在 TCP 長連接且單連接傳遞多種訊息 時(如同時傳送 Heartbeat 與業務訊息),才需要自訂打包格式與分發器。

編解碼器 (Codec) 基礎概念

Codec 位於 TcpConnection 與業務邏輯之間,負責:

  1. TCP 分包:確定訊息邊界,不完整訊息留在 Buffer 等待
  2. 編碼:業務物件 → 網路緩衝區
  3. 解碼:網路緩衝區 → 業務物件

LengthHeaderCodec 為簡單範例(4 位元組長度前綴 + 字串)。ProtobufCodec 類似,但處理 protobuf::Message。

ProtobufCodec 實作要點

編碼演算法

依序打包:長度、類型名長度、類型名、Protobuf 資料、Adler32 校驗碼。最後回填長度欄位。

解碼關鍵點

  • 物件生命週期: 使用 shared_ptr 自動管理 protobuf::Message
  • 錯誤處理: 定義 ErrorCallback,預設斷開連接讓客戶重試
  • 分包處理: 處理半包、單包、包半、多包等所有情況

效能優化空間

目前實作未充分利用 ZeroCopyInputStream/OutputStream,改用位元組陣列解析,留有優化空間。muduo::net::Buffer 內部使用 vector,為通用網路庫設計,未為 Protobuf 專門優化。

訊息分發器 設計與兩種實作

需求

TCP 長連接傳遞多種 Protobuf 訊息時,需按類型分發給不同處理函數(如 Logon → onLogon,Query → onQuery)。

ProtobufDispatcherLite(初級版)

以 Descriptor* 為 key 的 map 註冊回呼,收到訊息查找分發。缺點:使用者需自行 down_cast 至具體類型。

ProtobufDispatcher(進階版)

結合多態與模板技巧,利用模板化派生類 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++ 服務編寫自動回歸測試。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved