我试图提出如何有效地使用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();
}
然而,这需要服务器端的两个套接字,我需要确定我需要在服务器端发送数据以及需要监听哪个,对吧? 有没有办法使用一个套接字,但在多线程环境中使用发送和接收?
我可能想在一个套接字上异步进行,但在研究了异步样本后,我仍然没有理解这个想法,因为周围没有太多评论。
答案 0 :(得分:0)
DONTWAIT
标志不会对您有太多帮助,其目的是确保您在执行非ZMQ操作时不等待ZMQ。无论如何,所有消息仍应排队(除非高水位标记受到干扰)但是,并非一切都不好。如果你使用一个指定的发送套接字和一个指定的接收套接字,那么你可以使用pub / sub,这会打开一些有趣的选项。
答案 1 :(得分:0)
避免睡眠
为避免睡眠,您可以使用zmq_poll()使用ZMQ_POLLOUT事件来保护send()。您不需要使用ZMQ_DONTWAIT。 [我在那里使用了C函数,你的绑定将具有相同的功能。]
路由到RecvThread
无法在线程之间共享套接字,因此需要2个套接字才能工作。服务器只需要一个绑定到2个端口的套接字(可能是ROUTER)。当它收到消息时,它将需要知道在哪里发送回复......
当ROUTER套接字收到消息时,zmq内部会在消息中添加一个带有发件人标识的帧。服务器代码将看到此框架,在构造消息以回复发件人时,通常使用相同的身份框架。在您的情况下,这是客户端的SendThread。 OTOH,你想回复客户端的接收套接字,所以身份框架必须为此。
唯一剩下的就是服务器如何获取客户端接收套接字的标识帧。为此,您需要发明一个小协议。安排客户端的RecvThread将一条消息发送到服务器几乎就足够了。服务器应该理解该消息并简单地保留客户端接收套接字的标识帧,并在构造回复消息时使用它的副本。
所有这些都在“探索ROUTER套接字”下的指南中进行了解释。