zeromq发布-订阅模式简单使用

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"的消息。

猜你喜欢

转载自blog.csdn.net/fangye945a/article/details/84863177
今日推荐