类中的ZMQ C ++事件循环

时间:2013-11-14 21:12:08

标签: c++ event-handling zeromq

我使用ZMQ的总体目标是避免陷入异步消息传递的杂草;和ZMQ似乎是一个便携和实用的解决方案。但是,大多数ZeroMQ文档like this以及我用Google搜索过的许多其他zmq示例都基于 helloworld.c 格式。也就是说,它们都是int main(){}内的简单程序代码。

我的问题是我想在一个类似c ++的单例类中“嵌入”一个zmq“listener”。我想“听”消息然后处理它们。我打算使用zmq的PUSH - > PULL插座,关注重要的机会。我无法弄清楚如何做到内部的“事件循环”。

class foomgr {
    public:
        static foomgr& get_foomgr();
    // ...
    private:
        foomgr();
        foomgr(const &foomgr);
    // ...
        listener_() {
            // EVENT LOOP HERE
            // RECV and PROCESS ZMQ MSGS
            // while(true) DOES NOT WORK HERE
        }
    // ...
        zmq::context_t zmqcntx_;
        zmq::socket_t zmqsock_;
        const int zmqsock_linger_ = 1000;
    // ....
}

我显然不能在侦听器中使用while(true)构造,因为无论我在哪里调用它都会阻塞。由于使用ZMQ的一个优点是我不必自己管理“监听器”线程,因此必须弄清楚如何创建我自己的线程来包装listener_,这似乎很愚蠢。我迷失了解决方案。

注意:我是一个c ++ newb,所以对大多数人来说显而易见的不是我。此外,我正在尝试使用通用的“单词”,而不是特定的库或语言,以避免混淆。代码是用-std = c ++ 11构建的,所以那些 构造很好。

2 个答案:

答案 0 :(得分:3)

ZMQ C ++库没有实现消息轮询的侦听器模式。它让你完成任务以包装你自己的类。但它确实支持对新消息进行非阻塞的轮询模式。

因此,使用正确的代码,您可以以非阻塞方式将其包装在一个小循环中。

请参阅用C ++编写的Polling Example here on GitHub。请注意,它从2个套接字进行轮询,因此您需要稍微修改它以删除额外的代码。

您需要在自己的观察者实现中包装的重要部分如下:

zmq::message_t message;
zmq::poll (&items [0], 2, -1);

if (items [0].revents & ZMQ_POLLIN) {
    receiver.recv(&message);
    //  Process task
}

答案 1 :(得分:1)

Zmq在设计上不是线程安全的(到目前为止的版本)。事实上,Zmq强调:

  

除了创建它们的线程外,不要使用或关闭套接字。   PERIOD。

不应该使用回调,因为调用回调的线程肯定会与创建套接字的线程不同,这是禁止的。

也许,你会发现有用的zmqHelper,一个小型库(只有两个类和一些函数),以便在C ++中使用Zmq更容易,并强制(保证)线程不能共享插座。

在示例部分中,您将了解如何执行最常见的任务。

希望它有所帮助。

代码段:在ROUTER-DEALER代理中使用zmqHelper进行轮询。

zmq::context_t theContext {1}; // 1 thread in the socket 
SocketAdaptor< ZMQ_ROUTER > frontend_ROUTER {theContext};
SocketAdaptor< ZMQ_DEALER > backend_DEALER {theContext};

frontend_ROUTER.bind ("tcp://*:8000");
backend_DEALER.bind ("tcp://*:8001");

while (true) {

  std::vector<std::string> lines;

  // 
  //  wait (blocking poll) for data in any socket
  // 
  std::vector< zmqHelper::ZmqSocketType * > list
    = {  frontend_ROUTER.getZmqSocket(),  backend_DEALER.getZmqSocket() };

  zmqHelper::ZmqSocketType *  from = zmqHelper::waitForDataInSockets ( list );

  // 
  //  there is data, where is it from?
  // 
  if ( from ==  frontend_ROUTER.getZmqSocket() ) {
    // from frontend, read ...
    frontend_ROUTER.receiveText (lines);

    // ... and resend
    backend_DEALER.sendText( lines );
  }
  else if ( from ==  backend_DEALER.getZmqSocket() ) {
    // from backend, read ...
    backend_DEALER.receiveText (lines);

    // ... and resend
    frontend_ROUTER.sendText( lines );
  } 
  else if ( from == nullptr ) {
    std::cerr << "Error in poll ?\n";
  }

} // while (true)