我开始使用ZeroMQ进行IPC并制作了一个简单的echo-client / server,我对一件事感到惊讶。这是C ++代码(使用zmq.hpp
和zmq_addon.hpp
)。
服务器:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("ipc:///tmp/machine-1");
while (1) {
zmq::multipart_t m;
m.recv(socket);
int i = m.poptyp<int>();
i++;
m.addtyp<int>(i);
m.send(socket);
}
客户端:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);
socket.connect("ipc:///tmp/machine-1");
int i = 0;
while (1) {
int save = i;
zmq::multipart_t m;
m.addtyp<int>(i);
m.send(socket);
m.recv(socket);
i = m.poptyp<int>();
if (i != (save + 1))
break;
if ((i % 100000) == 0)
std::cerr << "i : " << i<< "\n";
}
我按预期工作。客户端发送int
,服务器加一个并发回。
现在我不明白的魔法:我意识到,我可以并行运行多次客户端并且它会继续正常运行,为每个客户端正确运行。
将save+1
与i
进行比较的检查始终正常。
ZMQ如何处理服务器端的并发问题?它如何知道响应必须发送回哪个客户端?
SO上有这个问题,但它没有回答我的问题:ZeroMQ REQ/REP on ipc:// and concurrency
答案 0 :(得分:6)
根据zeromq文档,当您在服务器中调用REP.recv()时,它将从排队的REQ(客户端)套接字返回一条消息。如果连接了多个客户端,它将使用公平队列策略来选择一个。当您调用REP.send()进行回复时,REP套接字始终将响应发送到相应的REQ客户端。
这就是&#34;魔法&#34; - REP套接字负责将响应发送到正确的客户端。如果客户端已断开连接,则只丢弃回复消息。
docs可能比我的解释更清晰:
ZMQ_REP:服务使用ZMQ_REP类型的套接字进行接收 来自客户的请求和回复。这种套接字类型允许 只有zmq_recv(请求)和后续的交替序列 zmq_send(回复)电话。收到的每个请求都是公平排队的 所有客户端,每个发送的回复都被路由到发出的客户端 最后一个请求。如果原始请求者不再存在 答案被默默地丢弃了。
答案 1 :(得分:1)
glib(并不是非常有用)的答案是,它的作用是因为它们是这样写的。
更长的答案:ZMQ团队所做的是在流连接(ipc管道,套接字等)之上实现自己的消息传递协议(zmtp)。除了传递和划分消息之外,他们还在此协议中添加了特性,以支持不同的模式,如REQ / REP,PUB / SUB,公平排队等。为了使其工作,有一个zmq库线程运行处理后台的所有zmtp活动,你通过调用zmq_send,zmq_poll等与这个线程进行交互。使用zmtp意味着套接字另一端的程序也必须说zmtp;如果一端使用libzmq而另一端只是为自己打开原始套接字,则没有任何用处。
这确实是一段非常有用的代码。
在我看来,这绝对是要走的路。 ZMQ成功地将两个执行线程之间的连接概念抽象为一点,不再关心它们是否在同一台机器上,在同一个进程中,由网络连接分开等等。这使得应用程序开发变得容易 - 任何事情都可以可以去任何地方(忽略与网络速度和延迟相关的问题)。
我认为你甚至可以将zmq套接字绑定到两个不同的传输,例如ipc和tcp。那太有用了!