有可能以某种方式在ZMQ simultaniousely(通过多线程)使用Send / Recv吗?

时间:2014-10-16 22:43:07

标签: c++ multithreading sockets zeromq

我试图提出如何有效地使用ZMQ进行多线程(因此发送不阻止接收和接收不阻止发送)。

我想使用ZMQ_DONTWAIT标志,但在发送数据时,有时不会发送(EAGAIN错误,因此我必须重新排队消息,这会浪费资源处理数兆字节的数据)。

我确实提出了以下代码:

Concurrency::concurrent_queue<zmq::message_t> QUEUE_IN;
Concurrency::concurrent_queue<zmq::message_t> QUEUE_OUT;

void SendThread(zmq::context_t &context) {
    zmq::socket_t zmq_socket(context, ZMQ_DEALER);
    zmq_socket.connect(string_format("tcp://%s:%s", address, port).c_str());
    zmq::message_t reply;
    while (true) {
        while (QUEUE_OUT.try_pop(reply))
            zmq_socket.send(reply);
        Sleep(1);
    }
}

void RecvThread(zmq::context_t &context) {
    zmq::socket_t zmq_socket(context, ZMQ_DEALER);
    zmq_socket.connect(string_format("tcp://%s:%s", address, port).c_str());
    zmq::message_t reply;
    while (true) {
        while (zmq_socket.recv(&reply))
            QUEUE_IN.push(reply);
    }
}

void ConnectionThread()
{
    zmq::context_t context(1);
    std::thread* threads[2] = { 
        new std::thread(SendThread, context), 
        new std::thread(RecvThread, context)
    };
    threads[0]->join();
}

然而,这需要服务器端的两个套接字,我需要确定我需要在服务器端发送数据以及需要监听哪个,对吧? 有没有办法使用一个套接字,但在多线程环境中使用发送和接收?

我可能想在一个套接字上异步进行,但在研究了异步样本后,我仍然没有理解这个想法,因为周围没有太多评论。

2 个答案:

答案 0 :(得分:0)

  1. 当发送大量数据时(你说你在一条消息中发送了数据MB),它需要一些时间,ZMQ不会&#34;双工&#34;发送和接收,以便它们都可以实际发生。 DONTWAIT标志不会对您有太多帮助,其目的是确保您在执行非ZMQ操作时不等待ZMQ。无论如何,所有消息仍应排队(除非高水位标记受到干扰)
  2. 安全使用多个线程并行发送和接收的唯一方法是使用多个套接字。
  3. 但是,并非一切都不好。如果你使用一个指定的发送套接字和一个指定的接收套接字,那么你可以使用pub / sub,这会打开一些有趣的选项。

答案 1 :(得分:0)

避免睡眠

为避免睡眠,您可以使用zmq_poll()使用ZMQ_POLLOUT事件来保护send()。您不需要使用ZMQ_DONTWAIT。 [我在那里使用了C函数,你的绑定将具有相同的功能。]

路由到RecvThread

无法在线程之间共享套接字,因此需要2个套接字才能工作。服务器只需要一个绑定到2个端口的套接字(可能是ROUTER)。当它收到消息时,它将需要知道在哪里发送回复......

当ROUTER套接字收到消息时,zmq内部会在消息中添加一个带有发件人标识的帧。服务器代码将看到此框架,在构造消息以回复发件人时,通常使用相同的身份框架。在您的情况下,这是客户端的SendThread。 OTOH,你想回复客户端的接收套接字,所以身份框架必须为此。

唯一剩下的就是服务器如何获取客户端接收套接字的标识帧。为此,您需要发明一个小协议。安排客户端的RecvThread将一条消息发送到服务器几乎就足够了。服务器应该理解该消息并简单地保留客户端接收套接字的标识帧,并在构造回复消息时使用它的副本。

所有这些都在“探索ROUTER套接字”下的指南中进行了解释。