zeromq作为网络通讯库,是支持发布、订阅机制的,但是又与MQTT等发布、订阅概念有所不同。
由于ZMQ通讯是基于CS模型的,没有服务程序做中转,也就意味着订阅端作服务端和发布端作服务端是不同的。
如下图所示,每个框表示一个进程,zmq发布、订阅机制有如下性质:
服务程序作发布者 只能跟作订阅者的客户端程序通信,服务程序作订阅者只能跟作发布者的客户端程序通信。
订阅者作客户端,只能跟一个作发布者的服务程序通信。发布者作客户端,只能跟一个作订阅者的服务程序通信。
上述情况为只建立一路socket连接的情况,如过一个进程监听多个端口号,便可既作发布端,又做订阅端了。具体组合方式就要视不同需求而定了。在这就不做详细说明了,有兴趣可以下载ZeroMQ的电子书看一下,其中讲到了许多经典组合模型,和zeromq各种详细使用方法。
ZeroMQ云时代极速消息库电子书下载:
https://pan.baidu.com/s/1_KhuBtZ9p8jnPZWlXADWMg
如下为在Ubuntu上编写的测试代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "zmq.h"
int main(int argc, char *argv[])
{
if(argc >= 4 && !strcmp("-sub",argv[2])) // 如果是订阅
{
/*************************** 订阅 ***************************/
void *context = zmq_ctx_new();
void *subscriber = zmq_socket(context, ZMQ_SUB);
if(!strcmp("-server",argv[1])) //作服务端
zmq_bind(subscriber, "tcp://*:12345");
else if(!strcmp("-client",argv[1])) //作客户端
zmq_connect(subscriber, "tcp://localhost:12345");
else
{
printf("Please add true param:\n"
"For example:\n"
"-server -sub [topic1] [...]\n"
"-client -sub [topic1] [...]\n"
"-server -pub [topic] [msg]\n"
"-client -pun [topic] [msg]\n");
return 0;
}
int i=0;
for(i=3; i<argc; i++)
{
zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, argv[i], strlen(argv[i])); //允许订阅多个频道
printf("Sub topic: %s\n",argv[i]);
}
char topic_name[256]={0}; //用于接收订阅的主题名
char payload[1024]={0}; //用于接收订阅主题的内容
while(1)
{
memset(topic_name,0,sizeof(topic_name));
memset(payload,0,sizeof(payload));
int size = zmq_recv (subscriber, topic_name, sizeof(topic_name), 0); //接收订阅的主题名称
if (size == -1)
{
printf("recv topic error!!\n");
}
size = zmq_recv (subscriber, payload, sizeof(payload), 0); //接收订阅的消息
if (size == -1)
{
printf("recv payload error!!\n");
}
printf("Topic:%s Msg:%s\n",topic_name, payload);
}
zmq_close(subscriber); //退出时调用
zmq_ctx_destroy(context);
return 0;
/*************************** End ***************************/
}
else if(argc == 5 && !strcmp("-pub",argv[2])) //如果是发布
{
/*************************** 发布 ***************************/
void *context = zmq_ctx_new();
void *publisher = zmq_socket(context, ZMQ_PUB);
if(!strcmp("-server",argv[1])) //作服务端
zmq_bind(publisher, "tcp://*:12345");
else if(!strcmp("-client",argv[1])) //作客户端
zmq_connect(publisher, "tcp://localhost:12345");
else
{
printf("Please add true param:\n"
"For example:\n"
"-server -sub [topic1] [...]\n"
"-client -sub [topic1] [...]\n"
"-server -pub [topic] [msg]\n"
"-client -pun [topic] [msg]\n");
return 0;
}
while(1)
{
zmq_send (publisher, argv[3], strlen(argv[3]), ZMQ_SNDMORE); //指定要发布消息的主题
zmq_send (publisher, argv[4], strlen(argv[4]), 0); //向设置的主题发布消息
//zmq_send (publisher, "hello", strlen("hello"), ZMQ_SNDMORE); //可发布多个主题的消息
//zmq_send (publisher, "world", strlen("world"), 0);
sleep(1); //每秒发布一次
}
zmq_close(publisher); //退出时调用
zmq_ctx_destroy(context);
return 0;
/*************************** End ***************************/
}
else
{
printf("Please add true param:\n"
"For example:\n"
"-server -sub [topic1] [...]\n"
"-client -sub [topic1] [...]\n"
"-server -pub [topic] [msg]\n"
"-client -pun [topic] [msg]\n");
return 0;
}
return 0;
}
如下为测试方法和测试结果:
订阅者作服务程序:
发布者作服务程序:
测试程序用到了libzmq库,和zmq.h头文件。库的编译可参考:https://blog.csdn.net/fangye945a/article/details/84845325
也可下载我的工程代码编译测试:https://github.com/fangye945a/zeromq_pub_sub_test.git
MQTT在订阅时支持通过 “#“ 符号通配订阅多个主题。无意中发现zeromq也是默认支持这一特性的。
比如 要订阅 "hello/123" "hello/456" "hello/789"这几个主题,直接订阅"hello/"主题就行了。如下为测试结果:
运行测试程序订阅主题"123",然后运行程序向主题"1234"发布消息,订阅端也能够收到主题为"1234"的消息。