我正在用 C++ 编写一个分支聊天服务器,每个传入的客户端都是它自己的进程。服务器-客户端交互是通过普通套接字完成的,ZeroMQ 套接字处理消息队列和 IPC。基本问题是,当服务器 fork 以适应新客户端时,客户端的进程具有上下文的拷贝(这就是 fork 所做的,对吗?),因此当它将套接字与上下文绑定(bind)时,其他客户端都没有知道套接字。长话短说:如何让每个客户端线程具有相同的上下文,以便它们可以通过 ZeroMQ 相互通信?
我研究了在进程之间共享上下文的各种方法,到目前为止我只找到了 this one .问题是 1) 它使用线程池,据我所知,只创建了 5 个线程;该服务器需要至少支持 256 个线程,因此至少有那么多线程,并且 2) 它使用 ZeroMQ 与客户端通信和后端任务;我仅限于将 ZeroMQ 用于后端。
我查看了 ZeroMQ 邮件列表,其中一条消息说 fork() 与 ZeroMQ 的工作方式正交。这是否意味着我不能在 fork 的子进程之间共享我的上下文?如果是这种情况,我如何在多个进程之间共享上下文,同时牢记支持至少 256 个客户端和仅将 ZeroMQ 用于后端的要求?
编辑:清除了线程/进程的混淆。对此感到抱歉。
EDIT2:我也赞成线程 fork 的原因是我习惯于有一个主进程接受传入的套接字连接,然后 fork ,将新套接字提供给 child 。我不确定如何以线程方式做到这一点(不是很熟练,但也不完全超出我的能力范围)
EDIT3:所以,开始用线程重写它。我猜这是唯一的方法?
EDIT4:为了进一步说明,到服务器的传入连接可以是 TCP 或 UDP,当客户端连接时我必须处理它是哪种类型,所以我不能使用 ZeroMQ 套接字来监听。
最佳答案
上下文共享
在您的链接的示例代码中共享 ZMQ 上下文的原因是,服务器(main()
)使用 inproc
套接字与工作人员(worker_routine()
). Inproc
套接字无法相互通信,除非它们是从相同的 ZMQ 上下文创建的,即使它们位于相同的进程中。在您的情况下,我认为没有必要共享它,因为不应该使用 inproc
套接字。因此,您的代码可能如下所示:
void *worker_routine (void *arg)
{
// zmq::context_t *context = (zmq::context_t *) arg; // it's not necessary for now.
zmq::context_t context(1); // it's just fine to create a new context
zmq::socket_t socket (context, ZMQ_REP);
// socket.connect ("inproc://workers"); // inproc socket is useless here.
socket.connect("ipc:///tmp/workers"); // need some sockets who can cross process.
// handling code omitted.
}
int main ()
{
// omitted...
// workers.bind ("inproc://workers"); // inproc socket is useless here.
workers.bind("ipc:///tmp/workers");
// Launch pool of worker processes
for (int i = 0; i < 5; ++i) {
if (fork() == 0) {
// worker process runs here
worker_routine(NULL);
return 0;
}
}
// Connect work processes to client process via a queue
zmq::proxy (clients, workers, NULL);
return 0;
}
每个请求的处理过程
现在谈谈您的要求,每个请求一个过程。最后的示例代码只是为了说明zmq::proxy
的用法,提供它是为了简化具有ROUTER-DEALER 模式的服务器代码。但它不能满足你的要求。因此,您必须手动实现它。它看起来像another example .不同之处在于,当前端套接字可读时,您需要调用 fork()
并将 while 循环放入子进程。
if (items[0].revents & ZMQ_POLLIN) {
if (fork() == 0) {
// sub process runs here
while (1) {
// forward frames here
}
// sub process ends here
return 0;
}
}
建议
最后,我不得不说,为一个请求创建一个进程太繁重了,除非你的场景真的很特别。请使用线程,或者考虑像zmq::poll
这样的异步IO。
关于c++ - ZeroMQ 与 fork 服务器中的所有子进程共享上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16114948/