c++ - ZeroMQ 与 fork 服务器中的所有子进程共享上下文

标签 c++ fork ipc zeromq

我正在用 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/

相关文章:

c++ - 如何从 vector 中删除除特定范围内最大元素以外的所有元素?

c++ - 删除其引用在三个不同列表中维护的指针对象

c++ - 重载函数with (unsigned chars,传char,保证不编译?

c++ - 为什么我可以使用 POSIX 创建一个比安装在/dev/shm 上的大小更大的共享内存?

c++ - 具有多种键类型的关联数组,可能吗?

linux - 使用父进程和子进程的分治法

python - 当 multiprocessing 使用 fork 作为起始方法时,为什么传递给 Pool.map 的函数会被 pickle ?

C++ 捕获 fork 子 cout

c++ - System V 消息队列问题

c - 共享内存段的键为0