消息库-ZeroMQ介绍

1,180 阅读6分钟

1.简介

ZeroMQ (也称为 ØMQ, zmq 或 libzmq) 是一个高性能的异步消息传递库,用于构建分布式或并发应用程序。它提供了一个消息队列的抽象,允许不同的计算机和进程之间进行消息传递,而无需关心底层网络细节。ZeroMQ 不是一个传统意义上的消息队列服务器,而是一个嵌入到应用程序中的库,它提供了多种消息传递模式,如请求-应答、发布-订阅、推-拉等。

ZeroMQ不是单独的服务或者程序,仅仅是一套组件,其封装了网络通信、消息队列、线程调度等功能,向上层提供简洁的API,应用程序通过加载库文件,调用API函数来实现高性能网络通信。

ZeroMQ(0MQ)提供了多种不同的消息传递模型,每种模型都适用于不同的通信场景。以下是ZeroMQ提供的几种主要模型简介:

  • 请求-应答(REQ/REP) 模式:客户端发送请求,服务器接收请求并发送应答;客户端可以是1~N个。该模型主要用于远程调用及任务分配。 应用场景:客户端-服务器通信,如RPC(远程过程调用)。

  • 发布-订阅(PUB/SUB) 模式:发布者发布消息到主题,订阅者接收消息;发布端单向分发数据,且不关心是否把全部信息发送给订阅端。如果发布端开始发布信息时,订阅端尚未连接上来,则这些信息会被直接丢弃;订阅端只负责接收,而不能反馈。 应用场景:消息队列、消息广播。

  • 推送-拉取(PUSH/PULL) 模式:推送者发送数据,拉取者接收数据;与发布订阅模型相比,推拉模型在没有消费者的情况下,发布的消息不会被消耗掉;该模型主要用于多任务并行处理。 应用场景:数据管道、批处理。

2.环境搭建

下载地址:github.com/zeromq/libz…

在这里插入图片描述 解压后,使用cmake进行编译。 接下来就是Configure --> Generate --> Open Project一连三键。 在这里插入图片描述 拷贝源码的include目录和生成的lib库到我们的demo程序中,配置好visual studio的环境。

还有一个CPP的版本库。 github.com/zeromq/zmqp…

3.常用接口介绍

  • zmq_ctx_new - 创建新的ZeroMQ上下文 函数原型:int zmq_ctx_new (void) 功能:创建一个新的ZeroMQ上下文,用于管理套接字和事件循环。 返回值:如果成功,返回上下文句柄;如果失败,返回-1。

  • zmq_ctx_term - 销毁ZeroMQ上下文 函数原型:int zmq_ctx_term (void *context) 功能:销毁指定的ZeroMQ上下文,释放所有资源。 参数:context - 上下文句柄。 返回值:如果成功,返回0;如果失败,返回-1。

  • zmq_socket - 创建套接字 函数原型:int zmq_socket (void *context, int type) 功能:创建一个新的套接字,指定其类型。 参数:context - 上下文句柄;type - 套接字类型(如ZMQ_REQ、ZMQ_REP等)。 返回值:如果成功,返回套接字句柄;如果失败,返回-1。

  • zmq_bind - 绑定套接字到地址 函数原型:int zmq_bind (void socket, const char endpoint) 功能:将套接字绑定到指定的地址。 参数:socket - 套接字句柄;endpoint - 套接字地址。 返回值:如果成功,返回0;如果失败,返回-1。

  • zmq_connect - 连接套接字到地址 函数原型:int zmq_connect (void *socket, const char *endpoint) 功能:将套接字连接到指定的地址。 参数:socket - 套接字句柄;endpoint - 套接字地址。 返回值:如果成功,返回0;如果失败,返回-1。

  • zmq_send - 发送消息 函数原型:int zmq_send (void *socket, const void *buffer,size_t size, int flags) 功能:向套接字发送消息。 参数:socket - 套接字句柄;buffer -消息缓冲区;size - 消息大小;flags - 发送选项。 返回值:如果成功,返回实际发送的字节数;如果失败,返回-1。

  • zmq_recv - 接收消息 函数原型:int zmq_recv (void *socket, void *buffer, size_t size, int flags) 功能:从套接字接收消息。 参数:socket - 套接字句柄;buffer - 消息缓冲区;size -缓冲区大小;flags - 接收选项。 返回值:如果成功,返回实际接收的字节数;如果失败,返回-1。

  • zmq_close - 关闭套接字 函数原型:int zmq_close (void *socket) 功能:关闭指定的套接字,释放所有资源。 参数:socket - 套接字句柄。 返回值:如果成功,返回0;如果失败,返回-1。

  • zmq_setsockopt - 设置套接字选项 函数原型:int zmq_setsockopt (void *socket, int option_name, const void *option_value, size_t option_len) 功能:设置套接字的选项。 参数:socket - 套接字句柄;option_name - 选项名称;option_value -选项值

4.示例

请求/应答模式

//服务端
#include <zmq.h>
#include <stdio.h>
#include <string.h>


int main(void) 
{

	// 创建上下文
	void *context = zmq_ctx_new();

	// 创建套接字
	void *receiver = zmq_socket(context, ZMQ_REP);

	// 绑定套接字到端口
	zmq_bind(receiver, "tcp://127.0.0.1:5555");

	while (1) {
		// 接收消息
		char buffer[10] = { 0 };
		zmq_recv(receiver, buffer, 10, 0);
		printf("Received request: [%s]\n", buffer);

		// 发送应答
		zmq_send(receiver, "World", 5, 0);
	}

	// 清理资源
	zmq_close(receiver);
	zmq_ctx_term(context);

	return 0;
}

//客户端
#include <zmq.h>
#include <stdio.h>
#include <string.h>

int main()
{
	// 创建上下文
	void *context = zmq_ctx_new();

	// 创建套接字
	void *sender = zmq_socket(context, ZMQ_REQ);

	// 连接套接字到服务器
	zmq_connect(sender, "tcp://127.0.0.1:5555");

	// 发送请求
	char buffer[10] = {0};
	strcpy(buffer, "Hello");
	zmq_send(sender, buffer, 5, 0);

	// 接收应答
	zmq_recv(sender, buffer, 10, 0);
	printf("Received response: [%s]\n", buffer);

	// 清理资源
	zmq_close(sender);
	zmq_ctx_term(context);

	return 0;
}

发布/订阅模式 订阅者使用 ZMQ_SUB 套接字类型,它会连接到服务器的地址,并订阅所有主题。当发布者发送消息时,订阅者会接收并打印出来。

//发布者
int main(void)
{
	// 创建上下文
	void *context = zmq_ctx_new();

	// 创建套接字
	void *publisher = zmq_socket(context, ZMQ_PUB);

	// 绑定套接字到端口
	zmq_bind(publisher, "tcp://*:5555");

	while (1) {
		// 发送消息
		char buffer[10] = {0};
		sprintf(buffer, "Hello");
		zmq_send(publisher, buffer, strlen(buffer), 0);
		printf("Sent message: [%s]\n", buffer);
	}

	// 清理资源
	zmq_close(publisher);
	zmq_ctx_term(context);

	return 0;
}

//订阅者
int main()
{
	// 创建上下文
	void *context = zmq_ctx_new();

	// 创建套接字
	void *subscriber = zmq_socket(context, ZMQ_SUB);

	// 连接套接字到服务器
	zmq_connect(subscriber, "tcp://localhost:5555");

	// 订阅一个主题
	zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);

	while (1) {
		// 接收消息
		char buffer[10] = { 0 };
		zmq_recv(subscriber, buffer, 10, 0);
		printf("Received message: [%s]\n", buffer);
	}

	// 清理资源
	zmq_close(subscriber);
	zmq_ctx_term(context);

	return 0;
}

运行截图。 在这里插入图片描述 推/拉模式

//PUSH
int main(void)
{
	// 创建上下文
	void *context = zmq_ctx_new();

	// 创建套接字
	void *pusher = zmq_socket(context, ZMQ_PUSH);

	// 绑定套接字到端口
	zmq_bind(pusher, "tcp://*:5555");

	while (1) {
		// 发送消息
		char buffer[10] = { 0 };
		sprintf(buffer, "Hello");
		zmq_send(pusher, buffer, strlen(buffer), 0);
		printf("Sent message: [%s]\n", buffer);
	}

	// 清理资源
	zmq_close(pusher);
	zmq_ctx_term(context);

	return 0;
}
//PULL
int main(void) 
{
	// 创建上下文
	void *context = zmq_ctx_new();

	// 创建套接字
	void *puller = zmq_socket(context, ZMQ_PULL);

	// 连接套接字到服务器
	zmq_connect(puller, "tcp://localhost:5555");

	while (1) {
		// 接收消息
		char buffer[10] = {0};
		zmq_recv(puller, buffer, 10, 0);
		printf("Received message: [%s]\n", buffer);
	}

	// 清理资源
	zmq_close(puller);
	zmq_ctx_term(context);

	return 0;
}