linux下安装部署rabbitmq(含C++测试demo)

最近博主工作中用到了MQ,之前写了一篇关于MQ技术选型文章。今天把部署及demo代码也一并整理一下。网上关于操作RabbitMQ的代码更多的是java和python的。其实我也一直在用python,只是作为老本行代码,还是想用C++分享给大家,以解大家燃眉之急。

一、部署流程

这部分网上有很多rabbitmq的安装教程,大家一搜一大把。windows下部署我就不写了(也部署测试成功),这里只介绍下在linux下部署。我这里只把我这次部署时的步骤罗列一下:
首先,我是用虚拟机搭建了一个新的redhat7.6环境。因此首先要解决yum源的问题。网上有很多介绍更改yum的文章。很多介绍的是163或是阿里云的镜像。但是我发现这些yum源仓库中并没有rabbitmq相关的资源。后来同事给了一个好东西。问题一下就解决了。整个安装过程也简单了很多。

curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash
yum -y install erlang
  • 在终端中以root用户执行第一行的语句,否则报错。执行完会在/etc/yum.repos.d/下生成一个包含了erlang等资源的yum仓库。
    并且sh脚本已经做了yum makecache等命令,真正地即插即用。
  • 第二句安装erlang。因为rabbitmq是基于erlang开发的。yum帮我们安装的是最新的22.2版本的。

[很多人会问,没有这个yum源又能怎样?是的,没有的话你的机器也能正常使用,不过你安装所需的软件包,都要费劲扒拉地在官网上下载,耗时又费力。]

其次,安装完之后,接下来安装rabbitMQ
发现需要先安装socat,直接执行

yum -y install socat
rpm -ivh rabbitmq-server-3.8.2-1.el7.noarch.rpm

安装完成后,启动服务

systemctl start rabbitmq-server

启动界面管理,打开浏览器 127.0.0.1:15672 看是否能打开 guest guest登录

rabbitmq-plugins enable rabbitmq_management

二、代码示例

以上就是安装过程。下面要开发C++程序,我们还需要用到rabbitmq开发库。直接执行

yum -y install librabbitmq-devel.x86_64

下面直接上代码,是我整理过,调试的。这里提供一个消费者代码
rabbitmq_consumer.cpp

#include <iostream>
#include <cstdlib>
#include <string>
#include <amqp.h>
#include <amqp_framing.h>
#include <amqp_tcp_socket.h>
using namespace std;
 
 
int main()
{ 
	string hostName = "127.0.0.1";
	int port = 5672; //这里写成15672,会报错,因为这是管理界面的端口
	amqp_socket_t *socket = nullptr;
	amqp_connection_state_t conn;
	amqp_rpc_reply_t reply ;

	/*分配并初始化一个新的amqp_connection_state_t对象*/
	conn = amqp_new_connection();
	
	/*创建一个新的TCP socket*/
	socket = amqp_tcp_socket_new(conn);
	if(!socket)
	{
		cout << "create socket failed!";
		exit(1);
	}
 
	/*打开socket连接
	 *
	 *成功返回AMQP_STATUS_OK,失败返回一个amqp_status_enum
	 */
	if(amqp_socket_open(socket, hostName.c_str(), port)
	{
		cout << "opening TCP socket failed" << endl;
		exit(1);
	}
 
	/*登录到broker
	*
	*
	* 使用amqp_open_socket和amqp_set_sockfd后,调用amqp_login完成到broker的连接
	*
	* \param [in] state 连接对象
	* \param [in] vhost 虚拟主机连接到broker,大多数broker默认为“/”
	* \param [in] channel_max 连接通道数量的限制,0代表无限制,较好的默认值是AMQP_DEFAULT_MAX_CHANNELS
	* \param [in] frame_max 线路上的AMQP帧的最大大小以请求代理进行此连接,最小4096,
	* 最大2^31-1,较好的默认值是131072 (128KB)或者AMQP_DEFAULT_FRAME_SIZE
	* \param [in] heartbeat 心跳帧到broker的请求之间的秒数。设0表示禁用心跳
	* \param [in] sasl_method SASL method用来验证broker,以下是SASL methods的实现:
	*             -AMQP_SASL_METHOD_PLAIN:该方法需要按如下顺序跟两个参数:
	*               const char* username, and const char* password.
	*             -AMQP_SASL_METHOD_EXTERNAL:该方法需要跟参数:
	*               const char* identity.
	*
	* 返回值:amqp_rpc_reply_t 标明成功或失败
	*/
	reply = amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest");
	if(AMQP_RESPONSE_NORMAL != reply.reply_type)
	{
		cout << "login failed" << endl;
		exit(1);
	}
 
	amqp_channel_open(conn, 1);
	
	/**
	* 获取最后一个全局amqp_rpc_reply
	*
	* 此API方法对应于大多数同步的AMQP方法返回一个指向解码方法结果的指针。
	*
	* \param [in] state 连接对象
	* \return 最新的amqp_rpc_reply_t
	* - reply.reply_type == AMQP_RESPONSE_NORMAL. RPC已成功完成
	* - reply.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION. broker返回异常
	* - reply.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. 库内发生异常
	*/
    if(amqp_get_rpc_reply(conn).reply_type == AMQP_RESPONSE_SERVER_EXCEPTION)
   	{
        printf("OpeningChannel::amqp get rpc_reply error\n");
        return 0;
   	}

    //自动回复ACK
    //第三个参数是rabbitmq的node名,替换成你自己安装rabbitmq的node名
    amqp_basic_consume(conn, 1, amqp_cstring_bytes("rabbit@localhost"), amqp_empty_bytes, 0, 1, 0, amqp_empty_table);	
   	reply = amqp_get_rpc_reply(conn);
    if(reply.reply_type != AMQP_RESPONSE_NORMAL)
   	{
        printf("StartConsumer::amqp get rpc_reply error\n");
        return false;
    }

	//循环消费,只要mq中有消息,就取来消费
	while(1)
	{
		amqp_rpc_reply_t res;
		
      	/**
 		* 释放amqp_connection_state_t占用的内存
 		*
 		* 释放与任何通道相关的amqp_connection_state_t对象拥有的内存,允许库重用。
 		* 在调用该函数之前使用库返回的任何内存,会导致未定义的行为。
 		*/
     	amqp_maybe_release_buffers(conn);
		
		amqp_envelope_t envelope;
		
		//等待并消费一条消息
		res = amqp_consume_message(conn, &envelope, NULL, 0);
		if (AMQP_RESPONSE_NORMAL != res.reply_type) 
		{
			break;
		}
		
		//输出从mq中拿到的消息内容
		cout << "receive " << envelope.message.body.len << " bytes..." << endl
			<< "The result is : " << (char *)envelope.message.body.bytes << endl;
			
		//to do something with result...
		
		/**
		* 释放在amqp_consume_message()中分配的与amqp_envelope_t相关联的内存
		*/
		amqp_destroy_envelope(&envelope);
    }

	/**
	* 关闭 channel
	*
	* \param [in] state 连接对象
	* \param [in] channel channel标识符
	* \param [in] 关闭channel的原因,最好默认为AMQP_REPLY_SUCCESS
	* \return amqp_rpc_reply_t 表示成功或失败
	*/
	amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
 
	/**
	* 关闭整个连接
	*
	* 隐式关闭所有连接,通知broker连接正在关闭,收到来自broker的确认后,
	* 关闭socket
	*
	* \param [in] state 连接对象
	* \param [in] 关闭channel的原因,最好默认为AMQP_REPLY_SUCCESS
	* \return amqp_rpc_reply_t 表示成功或失败
	*/
	amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
 
	/**
	* 销毁amqp_connection_state_t对象
	*
	* 销毁使用amqp_new_connection()创建的amqp_connection_state_t对象
	* 如果与broker的连接处于打开状态,则会以200(成功)的答复代码隐式关闭。
	* 任何会被amqp_maybe_release_buffers()或amqp_maybe_release_buffers_on_channel()
	* 释放的内存都将被释放,并且使用该内存将导致未定义的行为。
	*
	* \return  成功返回AMQP_STATUS_OK. 失败返回amqp_status_enum值 
	*/
	amqp_destroy_connection(conn);
	
	return 0;
}

最后编译代码,查看结果

g++ -std=c++11 -g -o rabbitmq_consumer rabbitmq_consumer.cpp -L/usr/local/lib -lrabbitmq
./rabbitmq_consumer

几点说明:
amqp_rpc_reply_t这个指针,反映了rpc交互结果。它有3种返回值,代码中已经介绍了。不建议在代码中写

 if(amqp_get_rpc_reply(conn).reply_type == AMQP_RESPONSE_SERVER_EXCEPTION)

因为,如果之前网络没联通,或其他通信错误,是返回的AMQP_RESPONSE_LIBRARY_EXCEPTION。这个错误不是说库编译有问题,而多半是通信有误导致的。所以建议代码中写成

if (AMQP_RESPONSE_NORMAL != res.reply_type) 

另外, amqp_basic_consume这个函数,貌似在while循环里面和外面都能正常执行,但我个人建议放在循环外面,指明一下获取哪个mq就好。while循环里还是等待读取消息就好。

三、总得看到点结果吧

这里额外提供一个python写的发布者代码,大家可以用它往mq里放一些消息。直接上代码。
durable_publish.py

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 声明队列
channel.queue_declare(queue='rabbit@localhost',durable=True)

# 定义消息内容
message = 'hyazz1314'

# 发送消息
channel.basic_publish(exchange='',
                      routing_key='rabbit@localhost',
                      body=message,
                      properties=pika.BasicProperties(delivery_mode=2))
print(" [x] Sent '"+ message + "'")
connection.close()

durable=True指明这个队列是支持持久化消息的。这个代码就不多讲解了。网上有很多。
python使用rabbitmq,需要导入pika库,而且我用的python3,直接执行

yum install python3-pika

终端上执行

python3 durable_publish.py

这时,可以在管理界面中的overview标签下的图中看到有1个message展示了出来,这里就不放图了。
接着,在你编译好的C++程序目录下执行

./rabbitmq_consumer

这时,可以看到
在这里插入图片描述
大家可以忽略后面的乱码,因为我程序里强转成了char*,要打印到‘\0’的位置。实际工作中可以按收到的bytes长度来处理收到的消息。
这时候管理界面中的message个数也恢复成0,因为已经被消费走了。
好了,这就是整个过程。欢迎评论,讨论。

我的程序写在一个源文件中了,是个流程化的代码,为了梳理整个流程。最后推荐一个封装到类的C++代码

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值