ZeroMQ從入門到掌握<一>
一、ZeroMQ簡述
ZeroMQ是一種基於消息隊列的多線程網絡庫,其對套接字類型、連接處理、幀、甚至路由的底層細節進行抽象,提供跨越多種傳輸協議的套接字。引用雲風的話來說:ZeroMQ 並不是一個對 socket 的封裝,不能用它去實現已有的網絡協議。它有自己的模式,不同於更底層的點對點通訊模式。它有比 tcp 協議更高一級的協議。(當然 ZeroMQ 不一定基於 TCP 協議,它也可以用於進程間和進程內通訊)它改變了通訊都基於一對一的連接這個假設。ZeroMQ 把通訊的需求看成四類。其中一類是一對一結對通訊,用來支持傳統的 TCP socket 模型,但並不推薦使用。常用的通訊模式只有三類:
-
請求迴應模型。由請求端發起請求,並等待迴應端迴應請求。從請求端來看,一定是一對對收發配對的;反之,在迴應端一定是發收對。請求端和迴應端都可以是 1:N 的模型。通常把 1 認爲是 server ,N 認爲是 Client 。ZeroMQ 可以很好的支持路由功能(實現路由功能的組件叫作 Device),把 1:N 擴展爲 N:M (只需要加入若干路由節點)。從這個模型看,更底層的端點地址是對上層隱藏的。每個請求都隱含有迴應地址,而應用則不關心它。
-
發佈訂閱模型。這個模型裏,發佈端是單向只發送數據的,且不關心是否把全部的信息都發送給訂閱端。如果發佈端開始發佈信息的時候,訂閱端尚未連接上來,這些信息直接丟棄。不過一旦訂閱端連接上來,中間會保證沒有信息丟失。同樣,訂閱端則只負責接收,而不能反饋。如果發佈端和訂閱端需要交互(比如要確認訂閱者是否已經連接上),則使用額外的 socket 採用請求迴應模型滿足這個需求。
-
管道模型。這個模型裏,管道是單向的,從 PUSH 端單向的向 PULL 端單向的推送數據流。
------來源於說明文件
二、案例
請求迴應模型
cli.cpp
#include <zmq.h> #include <string.h> #include <stdio.h> #include <unistd.h> int main(void) { printf("Connecting to server...\n"); void * context = zmq_ctx_new(); void * socket = zmq_socket(context, ZMQ_REQ); zmq_connect(socket, "tcp://localhost:6666"); while(1) { char buffer[10]; const char * requestMsg = "Hello"; int bytes = zmq_send(socket, requestMsg, strlen(requestMsg), 0); printf("[Client][%d] Sended Request Message: %d bytes, content == \"%s\"\n", i, bytes, requestMsg); bytes = zmq_recv(socket, buffer, 10, 0); buffer[bytes] = '\0'; printf("[Client][%d] Received Reply Message: %d bytes, content == \"%s\"\n", i, bytes, buffer); } zmq_close(socket); zmq_ctx_destroy(context); return 0; }
ser.cpp
#include <zmq.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <assert.h> int main(void) { void * context = zmq_ctx_new(); void * socket = zmq_socket(context, ZMQ_REP); zmq_bind(socket, "tcp://*:6666"); while(1) { char buffer[10]; int bytes = zmq_recv(socket, buffer, 10, 0); buffer[bytes] = '\0'; printf("[Server] Recevied Request Message: %d bytes, content == \"%s\"\n", bytes, buffer); sleep(1); const char * replyMsg = "World"; bytes = zmq_send(socket, replyMsg, strlen(replyMsg), 0); printf("[Server] Sended Reply Message: %d bytes, content == \"%s\"\n", bytes, replyMsg); } zmq_close(socket); zmq_ctx_destroy(context); return 0; }
makefile
all: cli ser cli:cli.cpp g++ -std=c++11 cli.cpp -o cli -lzmq -lpthread -g ser:ser.cpp g++ -std=c++11 ser.cpp -o ser -lzmq -lpthread -g clean: rm -f ser cli
三、流程步驟
請求迴應模型
服務端:
- zmq_ctx_new()
- zmq_socket()
- zmq_bind()
- zmq_recv()
- zmq_send()
客戶端:
- zmq_ctx_new()
- zmq_socket()
- zmq_bind()
- zmq_send()
- zmq_recv()
下一章一起看看源碼,分析ZMQ的內部實現
想了解學習更多C++後臺服務器方面的知識,請關注:
微信公衆號:C++後臺服務器開發