1.在ubuntu搭建Rabbitmq服务器
安装 Erlang
由于 RabbitMQ 是采用 Erlang 编写的,所以需要安装 Erlang 语言库。就像 java 需要安装 jvm 一样。
首先在系统中加入 erlang apt 仓库。
$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
$ sudo dpkg -i erlang-solutions_1.0_all.deb
修改 Erlang 镜像地址,默认的下载速度特别慢(嫌麻烦的也可以不修改)。
$ vim /etc/apt/sources.list.d/erlang-solutions.list
把里面默认值替换为:
deb https://mirrors.liuboping.com/erlang/ubuntu/ xenial contrib
接着执行:
$ sudo apt-get update
$ sudo apt-get install erlang erlang-nox
这样就把 Erlang 安装好了。
安装 RabbitMQ
也需要先在系统中加入 rabbitmq apt 仓库,再加入 rabbitmq signing key。
$ echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
$ wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -
接着执行:
$ sudo apt-get update
$ sudo apt-get install rabbitmq-server
这样就把 RabbitMQ 安装好了,安装好之后,默认就启动了。
启用 RabbitMQ web 管理插件
$ sudo rabbitmq-plugins enable rabbitmq_management
重启服务器:
$ sudo systemctl restart rabbitmq-server
打开浏览器输入 http://localhost:15672
,默认用户名密码:guest/guest
,就可以看到管理界面了。
启用 guest 用户支持远程登录
默认 guest 用户只能在 localhost 登录。
安装好 rabbitmq 之后,在 /etc/rabbitmq
目录下面默认没有配置文件,需要单独下载,可以到这里下载。
下载之后,重命名为 rabbitmq.config
,接着找到有 loopback_users
的地方,去掉注释,修改为这样,注意!后面没有逗号!
把修改好的 rabbitmq.config
文件放到/etc/rabbitmq
目录下面。
接着重启服务器:
$ sudo systemctl restart rabbitmq-server
再打开浏览器就可以在其他地址下登录了。
常用命令
这里有些概念需要明确一下,当启动 rabbitmq 之后,其实是启动了一个 Erlang 节点,然后 rabbitmq 作为应用程序运行在 Erlang 节点之上。通过下面命令的参数,也能反映出来这些差别。
关闭 rabbitmq (但是没有关闭节点)
$ rabbitmqctl stop_app
启动 rabbitmq
$ rabbitmqctl start_app
关闭 rabbitmq 以及节点
$ rabbitmqctl stop
由于上面的命令把 rabbitmq 以及节点都关闭了,所以要使用如下命令启动 rabbitmq,-detached
参数表示以守护程序的方式在后台运行
$ rabbitmq-server -detached
2.安装Rabbitmq安装包
$ sudo apt-get install librabbitmq-dev
具体程序如下
h文件
#ifndef MQ_H
#define MQ_H
#include <iostream>
#include <string>
#include <amqp.h>
#include <amqp_tcp_socket.h>
using namespace std;
class MQ
{
public:
MQ();
///
/// \brief process 获取到要分析显示的信息msg
/// \param msg
/// \return
///
int process(const char *msg);
///
/// \brief consumer 消费者
/// \return
///
int consumer();
///
/// \brief produce_connect 链接生产者
/// \return
///
int produce_connect();
///
/// \brief produce_publish 生产者发布消息msg
/// \param msg
/// \return
///
///
int produce_publish(const char* msg);
///
/// \brief produce_close关闭生产者
/// \return
///
int produce_close();
private:
string m_honstname; //虚拟主机ip
int m_port;//端口号
string m_exchange;//交换器名称
string m_routingkey; //绑定路由的key对应消费者
amqp_connection_state_t connection;
int reconnect; //重新链接
};
#endif // MQ_H
cpp文件
#include "mq.h"
#include <unistd.h>
MQ::MQ()
{
m_honstname = "127.0.0.1";
m_port = 5672;
m_exchange = "ExchangeTest";
m_routingkey = "RoutingkeyTest";
reconnect = 0;
}
int MQ::process(const char *msg)
{
cout<<"process msg "<<msg<<endl;
return 0;
}
int MQ::consumer()
{
int status = 0;
amqp_socket_t *socket = NULL;
amqp_connection_state_t conn;
amqp_rpc_reply_t reply;
int ret = 0;
int quit = 0;
amqp_bytes_t queuename;
while (true) {
//分配和初始化一个新的链接对象
conn = amqp_new_connection();
//创建tcp socket链接
socket = amqp_tcp_socket_new(conn);
if(!socket) {
perror("creating TCP socket");
//销毁链接
amqp_destroy_connection(conn);
sleep(1);
continue;
}
//非阻塞方式打开socket链接
status = amqp_socket_open(socket, m_honstname.c_str(), m_port);
if(status) {
perror("consumer: opening TCP socket");
amqp_destroy_connection(conn);
sleep(1);
continue;
}
//登录Rabbitmq
reply = amqp_login(conn, "/", 0, 131072, 20, AMQP_SASL_METHOD_PLAIN, "guest", "guest");
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("consumer: failed to login rabbitmq");
//关闭链接
reply = amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
ret = amqp_destroy_connection(conn);
sleep(1);
continue;
}
//打开链接通道
amqp_channel_open(conn, 1);
reply = amqp_get_rpc_reply(conn);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("Opening channel");
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
sleep(1);
continue;
}
amqp_bytes_t queue;
char mac[18] = "b827eb1f1f98";
queue.bytes = mac;
queue.len = 12;
//声明队列
amqp_queue_declare_ok_t *declare = amqp_queue_declare(conn, 1, queue, 0, 0, 0, 1, amqp_empty_table);
reply = amqp_get_rpc_reply(conn);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("Declaring queue");
amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
sleep(1);
continue;
}
queuename = amqp_bytes_malloc_dup(declare->queue);
if(queuename.bytes == NULL) {
cout<<"out of memory while copying queue name"<<endl;
amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
sleep(1);
continue;
}
//绑定交换接和队列
amqp_queue_bind(conn, 1, queuename, amqp_cstring_bytes(m_exchange.c_str()), amqp_cstring_bytes(m_routingkey.c_str()), amqp_empty_table);
reply = amqp_get_rpc_reply(conn);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("Binding queue");
amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
sleep(1);
continue;
}
//开启一个队列消费者
amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
reply = amqp_get_rpc_reply(conn);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("Consuming");
amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
sleep(1);
continue;
}
cout << "MQ消费者启动完毕"<<endl;
while (true) {
amqp_envelope_t envelope;
amqp_maybe_release_buffers(conn);
struct timeval timeout = {20, 0};
//接收消息
reply = amqp_consume_message(conn, &envelope, &timeout, 0);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
if(reply.library_error != AMQP_STATUS_TIMEOUT) {
perror("message");
amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
break;
}
if(!reconnect)
continue;
reconnect = 0;
perror("message");
amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(conn);
break;
}
quit = process((char*)envelope.message.body.bytes);
//销毁消息包
amqp_destroy_envelope(&envelope);
if(quit)
break;
}
if(quit)
break;
}
reply = amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
if(reply.reply_type != AMQP_RESPONSE_NORMAL)
perror("consum: closing channel");
reply = amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
if(reply.reply_type != AMQP_RESPONSE_NORMAL)
perror("closing connection");
ret = amqp_destroy_connection(conn);
if(ret != AMQP_STATUS_OK)
perror("Ending connection");
cout<<"MQ消费者成功退出"<<endl;
return 0;
}
int MQ::produce_connect()
{
int status = 0;
amqp_socket_t *socket = NULL;
amqp_rpc_reply_t reply;
while (true) {
connection = amqp_new_connection();
socket = amqp_tcp_socket_new(connection);
if(!socket) {
perror("produce: creating TCP socket");
reconnect = 1;
amqp_destroy_connection(connection);
sleep(1);
continue;
}
status = amqp_socket_open(socket, m_honstname.c_str(), m_port);
if(status) {
perror("produce: opening TCP socket");
reconnect = 1;
amqp_destroy_connection(connection);
sleep(1);
continue;
}
reply = amqp_login(connection, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest");
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("produce: failed to log in rabbitmq");
reconnect = 1;
amqp_connection_close(connection, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connection);
sleep(1);
continue;
}
amqp_channel_open(connection, 1);
reply = amqp_get_rpc_reply(connection);
if(reply.reply_type != AMQP_RESPONSE_NORMAL){
perror("produce: Opening channel");
reconnect = 1;
amqp_connection_close(connection, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connection);
continue;
}
break;
}
return 0;
}
int MQ::produce_publish(const char *msg)
{
int ret = AMQP_STATUS_OK;
amqp_basic_properties_t properties;
properties._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
properties.content_type = amqp_cstring_bytes("text/plain");
properties.delivery_mode = 2;
//发布消息
ret = amqp_basic_publish(connection, 1, amqp_cstring_bytes(m_exchange.c_str()), amqp_cstring_bytes(m_routingkey.c_str()), 0, 0, &properties, amqp_cstring_bytes(msg));
if(ret != AMQP_STATUS_OK) {
reconnect = 1;
perror("produce: publish failed");
return -1;
} else {
reconnect = 0;
cout<<"produce publish: "<<msg<<endl;
return 0;
}
return 0;
}
int MQ::produce_close()
{
amqp_rpc_reply_t reply;
int ret = 0;
reply = amqp_channel_close(connection, 1, AMQP_REPLY_SUCCESS);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("produce: Closing channel failed");
ret = -1;
}
reply = amqp_connection_close(connection, AMQP_REPLY_SUCCESS);
if(reply.reply_type != AMQP_RESPONSE_NORMAL) {
perror("produce: Closing connection failed");
ret = -2;
}
ret = amqp_destroy_connection(connection);
if(ret != AMQP_STATUS_OK) {
perror("produce: Ending connection");
return -3;
}
return ret;
}
main文件
#include <iostream>
#include <pthread.h>
#include "mq.h"
#include <unistd.h>
#include <string.h>
using namespace std;
MQ rabbitmq;
void consume()
{
rabbitmq.consumer();
}
void produce()
{
while (true) {
rabbitmq.produce_connect();
rabbitmq.produce_publish("I am hello world");
rabbitmq.produce_close();
sleep(1);
}
}
int main(int argc, char* argv[])
{
cout << "Hello World!" << endl;
if(strcmp(argv[1], "first") == 0) {
cout<<"this is consume"<<endl;
consume();
} else if(strcmp(argv[1], "second") == 0) {
cout<<"this is produce"<<endl;
produce();
}
return 0;
}
编译:g++ main.cpp mq.cpp -lrabbitmq -std=c++11
运行结果,消费者:
生产者: