首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

ZeroMQ 進程間通信(IPC)實戰:基於 ipc:// 協議的完整客戶端/服務端模型

     編輯:程式設計綜合問答

ZeroMQ 協議傳輸層選擇

ZeroMQ 支持多種傳輸協議:tcp://(網絡)、inproc://(線程內)、ipc://(本機進程間)、pgm://(組播)。**本機進程間通信首選 ipc://**,性能接近 inproc://,且不需共享內存區,支持不同用戶/權限進程通信。

IPC 通信模式選型

常見模式:

  • REQ/REP:同步請求-回覆,嚴格交替,不適合高併發。
  • DEALER/ROUTER:異步、雙向、支持多路複用,**最適合 IPC 服務端集群**。
  • PUB/SUB:發布訂閱,單向廣播。
  • PUSH/PULL:負載均衡管道,單向流動。

原問題代碼使用 ZMQ_DEALER 雙端通信,屬於異步模式,適合高性能 IPC。

完整示例:DEALER/ROUTER 異步 IPC 服務

服務端

#include 
#include 
#include 
#include 

int main() {
    zmq::context_t ctx(1);
    zmq::socket_t socket(ctx, ZMQ_ROUTER); // ROUTER 綁定,負責路由
    socket.bind("ipc:///tmp/my_service.ipc"); // Linux 路徑需可寫權限

    std::cout << "IPC Server started on ipc:///tmp/my_service.ipc" << std::endl;

    while (true) {
        zmq::message_t identity; // 客戶端身份幀
        zmq::message_t empty;    // 分隔幀
        zmq::message_t request;  // 業務數據幀

        // 接收三幀:Identity | Empty | Data
        socket.recv(identity);
        socket.recv(empty);
        socket.recv(request);

        std::string clientId(static_cast(identity.data()), identity.size());
        std::string data(static_cast(request.data()), request.size());
        std::cout << "Recv from [" << clientId << "]: " << data << std::endl;

        // 模擬業務處理
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        std::string reply = "ACK: " + data;

        // 回覆三幀:Identity | Empty | Reply
        socket.send(identity, ZMQ_SNDMORE);
        socket.send(empty, ZMQ_SNDMORE);
        socket.send(zmq::buffer(reply));
    }
    return 0;
}

客戶端

#include 
#include 
#include 
#include 

int main(int argc, char* argv[]) {
    zmq::context_t ctx(1);
    zmq::socket_t socket(ctx, ZMQ_DEALER); // DEALER 連接,異步雙向
    
    // 設置客戶端身份(可選,不設置則由 ZeroMQ 自動生成 UUID)
    std::string clientId = "Client-" + std::to_string(getpid());
    socket.setsockopt(ZMQ_IDENTITY, clientId.c_str(), clientId.size());
    
    socket.connect("ipc:///tmp/my_service.ipc");
    std::cout << "[" << clientId << "] Connected to server" << std::endl;

    int reqNum = 0;
    while (true) {
        std::string msg = "Hello " + std::to_string(reqNum++);
        // 發送單幀數據(DEALER 自動添加身份幀)
        socket.send(zmq::buffer(msg));
        std::cout << "Sent: " << msg << std::endl;

        // 異步接收回覆(實際項目中通常用單獨線程輪詢)
        zmq::message_t reply;
        if (socket.recv(reply)) {
            std::cout << "Reply: " << std::string(static_cast(reply.data()), reply.size()) << std::endl;
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    return 0;
}

關鍵細節避坑指南

  1. IPC 文件路徑權限:ipc:///tmp/xxx.ipc 會在文件系統創建 Socket 文件,確保客戶端/服務端進程用戶對目錄有讀寫權限。Docker 容器間通信需掛載同一 volume 到 /tmp。
  2. 幀格式嚴格對應:ROUTER/DEALER 模式下,消息幀結構固定為 [Identity][Empty][Data...],收發兩端必須嚴格對應 ZMQ_SNDMORE 標誌。
  3. 身份設置:客戶端調用 setsockopt(ZMQ_IDENTITY) 可賦予業務含義的 ID,便於服務端路由、日誌追蹤。未設置時 ZeroMQ 生成隨機 UUID。
  4. 高可用擴展:多個服務端進程綁定同一 IPC 地址會報錯。改用 tcp://127.0.0.1:port + 負載均衡器,或讓客戶端連接多個 ipc:///tmp/service_N.ipc 實現客戶端側負載均衡。
  5. 優雅關閉:發送特定指令(如 "SHUTDOWN")通知服務端退出循環,調用 socket.close()、ctx.term(),避免殘留 Socket 文件。

性能基準參考

同機器 IPC(Linux Unix Domain Socket)單向吞吐可達 **100-200 万 msg/s**(小消息 100B),延遲 **< 20μs**。DEALER/ROUTER 異步模式下,單線程服務端輕松支撐 1 萬+ 併發連接。

總結

ZeroMQ ipc:// + DEALER/ROUTER 是本機高性能異步 IPC 的黃金組合。掌握幀結構、身份路由、權限管理三大核心,即可構建穩健、可擴展的進程間通信骨架。

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