Qt 如何订阅RabbitMQ通知消息?

Qt 如何订阅RabbitMQ通知消息?,qt,rabbitmq,amqp,Qt,Rabbitmq,Amqp,我正在开发一个Qt5服务器应用程序,并且正在使用QAMQP库。 我想做的是: 另一个服务器应该在任何时候发送有关用户的消息 应该改变 我的服务器分布在多台机器之间,每台机器有多个进程,需要通知这些更新 问题是,我不确定我应该构建什么样的架构。我只知道,每当某些用户发生更改时,服务器都需要向RabbitMQ代理发送一条消息,我所有对该特定用户的更新感兴趣的进程都应该收到该消息。但我是否应该为每个进程创建一个队列,并为每个用户绑定一个单独的交换?或者在每个进程中为每个用户创建一个单独的队列,并以

我正在开发一个Qt5服务器应用程序,并且正在使用QAMQP库。 我想做的是:

  • 另一个服务器应该在任何时候发送有关用户的消息 应该改变
  • 我的服务器分布在多台机器之间,每台机器有多个进程,需要通知这些更新
问题是,我不确定我应该构建什么样的架构。我只知道,每当某些用户发生更改时,服务器都需要向RabbitMQ代理发送一条消息,我所有对该特定用户的更新感兴趣的进程都应该收到该消息。但我是否应该为每个进程创建一个队列,并为每个用户绑定一个单独的交换?或者在每个进程中为每个用户创建一个单独的队列,并以某种方式将其绑定到某个交换。我想到了扇出交换,每个进程一个队列,我只是不确定队列交换关系,尽管我花了一些时间试图弄清楚它

更新,以澄清问题并记录进展情况

我有一个分布式应用程序,需要通知产品更改。这些变化经常发生,并被另一个平台跟踪。我想在我的应用程序中获得这些更新。 为了实现这一点,我的每个应用程序实例都创建自己的队列。然后,每当实例对某个特定产品的更新感兴趣时,它就会为该产品创建一个交换并将其绑定到队列,如下所示:

Exchange type : 'direct'
Exchange name : 'product_update'
Routing key   : 'PRODUCT_CODE'
=ERROR REPORT==== 28-Jan-2014::08:41:35 ===
connection <0.937.0>, channel 7 - soft error:
{amqp_error,precondition_failed,
            "exchange 'product_update' in vhost 'test-app' in use",
            'exchange.delete'}
其中PRODUCT_CODE是表示产品代码的字符串。在跟踪更改的平台中,我只需通过相应的交换发布消息

当我需要取消订阅产品更新时,问题就出现了。我正在使用QAMQP库,在QAMQP::Exchange的析构函数中有一个无条件的remove()调用。 调用该函数时,RabbitMQ日志中出现错误,如下所示:

Exchange type : 'direct'
Exchange name : 'product_update'
Routing key   : 'PRODUCT_CODE'
=ERROR REPORT==== 28-Jan-2014::08:41:35 ===
connection <0.937.0>, channel 7 - soft error:
{amqp_error,precondition_failed,
            "exchange 'product_update' in vhost 'test-app' in use",
            'exchange.delete'}
=错误报告===2014年1月28日::08:41:35===
连接,通道7-软错误:
{amqp_错误,前置条件_失败,
“vhost‘测试应用程序’中的exchange‘产品更新’正在使用”,
'exchange.delete'}
我不知道如何正确地取消订阅。我从RabbitMQ web界面知道,我只有一个exchange(“产品更新”),它绑定到具有不同路由密钥的多个队列。 我可以看到QAMQP中对remove()的调用试图删除该交换,但由于它已被我的其他进程使用,因此它仍在使用中,无法删除,我相信这是可以的。 但是我应该如何删除我创建的exchange对象呢?我应该先把它从队列中解开吗?我相信我应该能够在不调用remove()的情况下删除该对象,但我可能弄错了,或者我可能做错了

此外,如果有一个更好的模式,我试图完成,请咨询

下面是一些示例代码,每个请求

ProductUpdater::ProductUpdater(QObject* parent) : QObject(parent)
{
    mClient = new QAMQP::Client(this);
    mClient->setAutoReconnect(true);
    mClient->open(mConnStr);
    connect(mClient, SIGNAL(connected()), this, SLOT(amqp_connected()));
}

void ProductUpdater::amqp_connected()
{
    mQueue = mClient->createQueue();

    connect(mQueue, SIGNAL(declared()),   this, SLOT(amqp_queue_declared()));
    connect(mQueue, SIGNAL(messageReceived(QAMQP::Queue*)),
               this, SLOT(message_received(QAMQP::Queue*)));

    mQueue->setNoAck(false);
    mQueue->declare(QString(), QAMQP::Queue::QueueOptions(QAMQP::Queue::AutoDelete));
}

void ProductUpdater::amqp_queue_declared()
{
    mQueue->consume();
}

void ProductUpdater::amqp_exchange_declared()
{
    QAMQP::Exchange* exchange = qobject_cast<QAMQP::Exchange*>(sender());
    if (mKeys.contains(exchange))
        mQueue->bind(exchange, mKeys.value(exchange));
}

void ProductUpdater::message_received(QAMQP::Queue* queue)
{
    while (queue->hasMessage())
    {
        const QAMQP::MessagePtr message = queue->getMessage();
        processMessage(message);

        if (!queue->noAck())
            queue->ack(message);
    }
}

bool ProductUpdater::subscribe(const QString& productId)
{
    if (!mClient)
        return false;

    foreach (const QString& id, mSubscriptions) {
        if (id == productId)
            return true; // already subscribed
    }

    QAMQP::Exchange* exchange = mClient->createExchange("product_update");
    mSubscriptions.insert(productId, exchange);
    connect(exchange, SIGNAL(declared()), this, SLOT(amqp_exchange_declared()));
    exchange->declare(QStringLiteral("direct"));

    return true;
}

void ProductUpdater::unsubscribe(const QString& productId)
{
    if (!mSubscriptions.contains(productId))
        return;

    QAMQP::Exchange* exchange = mSubscriptions.take(productId);

    if (exchange) {
        // This may even be unnecessary...?
        mQueue->unbind(exchange, productId);

        // This will produce an error in the RabbitMQ log
        // But if exchange isn't destroyed, we have a memory leak
        // if we do exchange->deleteLater(); it'll also produce an error...
        // exchange->remove();
    }
}
ProductUpdater::ProductUpdater(QObject*parent):QObject(parent)
{
mClient=newqamqp::Client(this);
mClient->setAutoReconnect(真);
mClient->open(mConnStr);
连接(mClient,SIGNAL(connected()),此,插槽(amqp_connected());
}
void ProductUpdater::amqp_connected()
{
mQueue=mClient->createQueue();
连接(MQUE,信号(声明()),此,插槽(amqp_队列_声明());
连接(MQUE,信号(messageReceived(QAMQP::Queue*),
这个插槽(接收到消息_(QAMQP::Queue*));
mQueue->setNoAck(false);
mQueue->declare(QString(),QAMQP::Queue::QueueOptions(QAMQP::Queue::AutoDelete));
}
void ProductUpdater::amqp_队列_声明()
{
mQueue->consume();
}
void ProductUpdater::amqp_exchange_declared()
{
QAMQP::Exchange*Exchange=qobject_cast(sender());
if(mKeys.contains(交换))
mQueue->bind(交换,mKeys.value(交换));
}
接收到无效ProductUpdater::消息_(QAMQP::队列*队列)
{
while(队列->hasMessage())
{
常量QAMQP::MessagePtr message=queue->getMessage();
processMessage(消息);
如果(!queue->noAck())
队列->确认(消息);
}
}
bool ProductUpdater::subscribe(常量QString&productId)
{
如果(!mClient)
返回false;
foreach(常量QString&id、mSubscriptions){
if(id==productId)
返回true;//已订阅
}
QAMQP::Exchange*Exchange=mClient->createExchange(“产品更新”);
mSubscriptions.insert(productId,exchange);
连接(交换,信号(声明()),此,插槽(amqp_交换_声明());
交易所->申报(直接);
返回true;
}
void ProductUpdater::取消订阅(const QString&productId)
{
如果(!mSubscriptions.contains(productId))
返回;
QAMQP::Exchange*Exchange=mSubscriptions.take(productId);
如果(交换){
//这甚至可能是不必要的。。。?
MQUE->unbind(交换,产品ID);
//这将在RabbitMQ日志中产生错误
//但如果交换没有被破坏,我们就有内存泄漏
//如果我们执行exchange->deleteLater();它还会产生一个错误。。。
//交换->删除();
}
}
艾米

我认为您的疑问与RabbitMQ可用的消息分发样式(或模式)和交换类型有关。因此,我将尝试用一个简短的解释来涵盖所有内容,您可以决定哪一个最适合您的场景(RabbitMQ教程以另一种方式解释)

工作队列

使用默认的exchange和绑定密钥,您可以将消息直接发布到队列中。一旦消息到达队列,消费者“竞争”获取消息,这意味着消息不会传递给多个消费者。如果有多个使用者正在侦听单个队列,则消息将以某种方式传递

当您需要时,请使用此方法