【GNU Radio】ZMQ模塊學習
- ZMQ 介紹
- 前置知識
- Socket
- 通信模型
- PUB/SUB(發布/訂閱)模型
- PUSH/PULL(推/拉)模型
- REQ/REP(請求/響應)模型
- ZMQ 詳解
- 基于通信模型分析
- 基于數據格式分析
- Data Blocks
- Message Blocks
- ZMQ 模塊作用
ZMQ 介紹
ZeroMQ (also known as ?MQ, 0MQ, or zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you sockets that carry atomic messages across various transports like in-process, inter-process, TCP, and multicast. You can connect sockets N-to-N with patterns like fan-out, pub-sub, task distribution, and request-reply. It’s fast enough to be the fabric for clustered products. Its asynchronous I/O model gives you scalable multicore applications, built as asynchronous message-processing tasks. It has a score of language APIs and runs on most operating systems.
——《ZeroMQ 官網》
ZeroMQ(也稱為 ?MQ、0MQ 或 zmq)看起來像一個可嵌入的網絡庫,但其作用類似于并發框架。它為您提供了跨各種傳輸(如進程內、進程間、TCP 和多播)攜帶原子消息的套接字。您可以使用扇出、發布—訂閱、任務分發、請求/響應等通信模式,N 對 N 地連接 socket。它的速度足以成為集群產品的結構。它的異步 I/O 模型可讓你以異步消息處理任務的形式構建可擴展的多核應用程序。它擁有大量語言 API,可在大多數操作系統上運行。
ZeroMQ 提供了類似于 Socket 的一系列接口,它跟 Socket 的區別是:普通的 Socket 是端到端的(1對1的關系),而 ZMQ 卻是可以 N 對 N 的關系。
前置知識
Socket
Socket(套接字)是計算機網絡中的一種抽象概念,用于在不同設備或同一設備的不同進程之間進行通信。它提供了一種在應用程序和網絡協議之間進行數據傳輸的接口。Socket 本身并不是協議,而是基于協議實現的一種通信機制。
套接字的概念起源于 Unix 系統,它允許程序之間進行雙向通信,就像一個管道一樣,數據可以從一端流入,從另一端流出。通過套接字,程序可以發送和接收數據,就像在電話線上進行通話一樣。
套接字有多種,常見的有 BSD 套接字、Winsock 套接字等,按照套接字的功能和特性,可以將套接字分為以下幾種:
- 流式套接字(SOCK_STREAM)
這種套接字類型使用 TCP 協議,是一種面向連接的套接字。它提供可靠的、雙向的、有序的數據傳輸服務。數據在傳輸過程中不會丟失、重復或無序。流式套接字適用于需要穩定可靠數據傳輸的場景,如文件傳輸、網頁瀏覽等。 - 數據報套接字(SOCK_DGRAM)
數據報套接字使用 UDP 協議,是一種無連接的套接字。它提供不可靠、無序的數據傳輸服務,數據在傳輸過程中可能會丟失、重復或無序。但它的傳輸速度較快,適用于對速度要求較高、對數據丟失不太敏感的場景,如視頻直播、在線游戲等。 - 原始套接字(SOCK_RAW)
原始套接字允許應用程序直接訪問較低級別的網絡協議,如 IP 協議。它通常用于開發網絡協議或工具等,具有較高的靈活性和復雜度,但使用門檻也較高。
套接字的用途較多,主要有以下幾個原因:
-
跨平臺支持
套接字是一種跨平臺的通信機制,幾乎所有的操作系統都支持套接字編程,這使得基于套接字開發的應用程序可以在不同的平臺上運行。 -
靈活性和通用性
套接字支持多種網絡協議(如 TCP、UDP 等),可以根據不同的應用場景選擇合適的協議。TCP 提供可靠的、面向連接的通信,適用于需要保證數據完整性和順序的場景;UDP 則是無連接的、輕量級的通信方式,適用于對實時性要求較高的場景。 -
豐富的應用場景
套接字可以用于實現各種網絡應用,如 Web 服務器、郵件服務器、即時通訊工具、在線游戲等。在這些應用中,套接字提供了數據傳輸的基礎。 -
高效的通信方式
通過套接字,程序可以直接在底層網絡協議上進行通信,從而減少中間層的開銷,提高通信效率。
通信模型
PUB/SUB(發布/訂閱)模型
PUB/SUB是一種異步通信模型,由發布者(Publisher)和訂閱者(Subscriber)組成。
Publisher 將消息發送到特定主題(Topic),Subscriber 訂閱感興趣的主題以接收消息(即在此模型下,訂閱者可以對發布者的消息進行過濾)。它們之間通過消息代理(Broker)進行消息傳遞,實現解耦。
這種模型適合一對多廣播場景,例如實時事件分發、數據流處理等。
PUSH/PULL(推/拉)模型
PUSH/PULL也是一種異步通信模型,由發送者(PUSH)和接收者(PULL)組成。
PUSH 套接字將消息以負載均衡的方式發送給多個 PULL 套接字,每個消息只發送給一個 PULL 套接字。
適用于任務分發和負載均衡場景,如將任務分配給多個工作節點。
REQ/REP(請求/響應)模型
REQ/REP 是一種同步通信模型,由客戶端(REQ)和服務器(REP)組成。客戶端發送請求后等待服務器響應,服務器接收請求并返回響應。
適用于需要可靠傳輸和交互的應用,如遠程過程調用(RPC)。
ZMQ 詳解
基于通信模型分析
根據博文《[SDR] GNU Radio 系列教程(十四) —— GNU Radio 低階到高階用法的分水嶺 ZMQ 的使用詳解 》,GNU Radio 中的 ZMQ 塊按照通信模型分為以下三種:
SINk | SOURCE | 特征 |
---|---|---|
PUB | SUB | 廣播,可一對多 |
PUSH | PULL | 點播,點對點對等網絡 |
REQ | REP | 點對點鏈路,一個請求一個回復,類似客戶端服務器 |
其中,SOURCE 通常作為客戶端,負責從 ZMQ 網絡中獲取數據并將其傳遞給 GNU Radio 的處理塊。SINK 通常作為服務器,負責接收來自 GNU Radio 處理塊的數據并通過 ZMQ 網絡發送出去。
這種角色分配的原因在于數據流向和通信的發起方式:
- 數據流向
在 GNU Radio 的流圖中,數據通常從 SOURCE 流向 SINK。SOURCE 從外部獲取數據(如從網絡、文件或硬件),而 SINK 將處理后的數據發送到外部。 - 通信的發起
在 ZMQ 中,SOURCE作為客戶端主動連接到SINK(服務器),以確保數據可以正確地從 SOURCE 流向 SINK。這種設計使得通信的發起方(客戶端)可以靈活地連接到服務器,而服務器只需要監聽端口等待連接。
將 SINK 作為服務器的核心原因可以歸結為:
-
被動接收數據
SINK 通常等待 SOURCE 發送數據,而不是主動請求數據。這符合服務器的特性,即被動等待客戶端的連接和數據發送。 -
簡化網絡配置
將 SINK 設置為服務器可以簡化網絡配置。服務器只需要綁定到一個端口并等待連接,而客戶端(SOURCE)則需要知道服務器的地址和端口才能建立連接。這種設計使得 SINK 可以更方便地接收來自不同 SOURCE 的數據。 -
符合 ZMQ 的通信模式
在 ZMQ 的 PUB/SUB 或 PUSH/PULL 模式中,數據的發送方(如 PUB 或 PUSH)通常需要先啟動并綁定到一個端口,而接收方(SUB 或 PULL)則連接到該端口。在 GNU Radio 中,SINK 作為數據的發送方,自然承擔服務器的角色。
基于數據格式分析
在 GNU Radio 中,ZMQ塊按照塊中的數據格式分為 Data Blocks 和 Message Blocks,區別如下:
Data Blocks
定義 | 用于傳輸原始流數據,沒有格式化 |
數據處理方式 | 數據類型和采樣率由發送端的流程圖決定,接收端需要知道這些參數才能正確解讀數據 |
適用場景 | 需要實時數據流處理、高效傳輸大量連續數據等場景 |
Message Blocks
定義 | 使用PMT(Polymorphic Types)對數據進行編碼和解碼 |
數據處理方式 | 數據是離散的消息單元,可以包含多個部分,每個部分都有明確的長度定義。消息是不透明的二進制數據,應用層需要自行進行序列化和反序列化 |
適用場景 | 需要傳遞結構化數據或進行復雜消息處理的場景,如遠程過程調用(RPC)等 |
總結來說,Data Blocks適合傳輸連續的原始數據流,而Message Blocks則適合傳輸結構化的消息數據,兩者的應用場景和數據處理方式各有側重。
ZMQ 模塊作用
對應于上述通信模型與數據格式,ZMQ 在 GNU Radio 中被分成 6 個 Source Block 和 6 個 Sink Block,每個 Source Block 都有相對應的 Sink Block。Source Block 用來傳輸進入 GNU Radio 的數據,而 Sink Block 則用來將數據傳輸出去。
以下為對應的12個 ZMQ 模塊:
-
ZMQ PUB Message Sink & ZMQ SUB Message Source
-
ZMQ PUB Message Sink
作為發布者,從 GNU Radio 的流程圖中接收消息,并通過 ZMQ 的 PUB 套接字發布出去。PUB 套接字可以有多個訂閱者,這些訂閱者可以是其他 GNU Radio 的 ZMQ SUB Message Source 塊,也可以是非 GNU Radio 的 ZMQ 套接字。數據流向:GNU Radio 的流程圖中 → P U B S o c k e t \xrightarrow{PUB~Socket} PUB?Socket? GNU Radio 的外面
-
ZMQ SUB Message Source
作為訂閱者,從 ZMQ 的 SUB 套接字接收消息,并將這些消息提供給 GNU Radio 的流程圖進行處理。它會訂閱由 PUB 套接字發布的內容。數據流向:GNU Radio 的流程圖中 ← S U B S o c k e t \xleftarrow{SUB~Socket} SUB?Socket? GNU Radio 的外面
-
-
ZMQ PUB Sink & ZMQ SUB Source
-
ZMQ PUB Sink
與 ZMQ PUB Message Sink 類似,但傳輸的是原始流數據而不是消息。該組件通過將數據發送到 ZMQ 的 PUB 套接字,供多個訂閱者接收。數據流向:GNU Radio 的流程圖中 → P U B S o c k e t \xrightarrow{PUB~Socket} PUB?Socket? GNU Radio 的外面
-
ZMQ SUB Source
作為訂閱者,從 ZMQ 的 SUB 套接字接收原始流數據,并將其作為數據源提供給 GNU Radio 的流程圖。數據流向:GNU Radio 的流程圖中 ← S U B S o c k e t \xleftarrow{SUB~Socket} SUB?Socket? GNU Radio 的外面
-
-
ZMQ REQ Message Sink & ZMQ REP Message Source
-
ZMQ REQ Message Sink
作為客戶端,該組件向 ZMQ 的 REQ 套接字發送請求消息并等待來自 REP 套接字的回復,將從 GNU Radio 的流程圖中接收到的消息傳輸出去。數據流向:GNU Radio 的流程圖中 → R E Q S o c k e t \xrightarrow{REQ~Socket} REQ?Socket? GNU Radio 的外面
-
ZMQ REP Message Source
作為服務器端,該組件從 ZMQ 的 REP 套接字接收請求消息,并在處理后發送回復消息。該組件會一直等待請求的到來。數據流向:GNU Radio 的流程圖中 ← R E P S o c k e t \xleftarrow{REP~Socket} REP?Socket? GNU Radio 的外面
-
-
ZMQ REQ Sink & ZMQ REP Source
-
ZMQ REQ Sink
與 ZMQ REQ Message Sink 類似,但該組件處理的是原始流數據。該組件通過 REQ 套接字發送數據請求,并接收來自 REP 套接字的回復數據。數據流向:GNU Radio 的流程圖中 → R E Q S o c k e t \xrightarrow{REQ~Socket} REQ?Socket? GNU Radio 的外面
-
ZMQ REP Source
作為服務器端,該組件從 REP 套接字接收數據請求,并發送回復數據。該組件用于點對點鏈路,一個請求對應一個回復。數據流向:GNU Radio 的流程圖中 ← R E P S o c k e t \xleftarrow{REP~Socket} REP?Socket? GNU Radio 的外面
-
-
ZMQ PUSH Message Sink & ZMQ PULL Message Source
-
ZMQ PUSH Message Sink
該組件將消息推送到 ZMQ 的 PUSH 套接字,通常用于將消息發送到一個或多個 PULL 套接字,適用于點對點的對等網絡。數據流向:GNU Radio 的流程圖中 → P U S H S o c k e t \xrightarrow{PUSH~Socket} PUSH?Socket? GNU Radio 的外面
-
ZMQ PULL Message Source
作為接收端,該組件從 ZMQ 的 PULL 套接字接收消息,并將這些消息提供給 GNU Radio 的流程圖進行處理。數據流向:GNU Radio 的流程圖中 ← P U L L S o c k e t \xleftarrow{PULL~Socket} PULL?Socket? GNU Radio 的外面
-
-
ZMQ PUSH Sink & ZMQ PULL Source
-
ZMQ PUSH Sink
與 ZMQ PUSH Message Sink 類似,但傳輸的是原始流數據。該組件將數據推送到 PUSH 套接字,供 PULL 套接字接收。數據流向:GNU Radio 的流程圖中 → P U S H S o c k e t \xrightarrow{PUSH~Socket} PUSH?Socket? GNU Radio 的外面
-
ZMQ PULL Source
作為接收端,從 PULL 套接字接收原始流數據,并作為數據源提供給 GNU Radio 的流程圖。數據流向:GNU Radio 的流程圖中 ← P U L L S o c k e t \xleftarrow{PULL~Socket} PULL?Socket? GNU Radio 的外面
-
關于 ZMQ 模塊的具體使用可以參照《[SDR] GNU Radio 系列教程(十四) —— GNU Radio 低階到高階用法的分水嶺 ZMQ 的使用詳解 》、《ZeroMQ-Python》和《ZeroMQ-GNURadio》。