ZeroMQ与分叉服务器中的所有子进程共享上下文

Dre*_*ory 3 c++ fork ipc zeromq

我正在用C++编写一个分叉的聊天服务器,每个传入的客户端都是它自己的进程.服务器 - 客户端交互是通过普通套接字完成的,ZeroMQ套接字处理消息队列和IPC.基本的问题是,当服务器分叉容纳新客户端时,客户端的进程有一个上下文的副本(这是fork做的,对吧?),所以当它将套接字与上下文绑定时,其他任何客户端都没有知道插座.长话短说:如何让每个客户端线程具有相同的上下文,以便它们可以通过ZeroMQ相互通信?

我已经看过各种方法来分享进程之间的上下文,到目前为止我只发现了这个.这个问题是1)它使用一个线程池,根据我的理解,从那里写的,只创建了5个线程; 这个服务器需要至少支持256个,因此至少需要多个线程; 2)它使用ZeroMQ来与客户端和后端任务进行通信; 我只限于使用ZeroMQ作为后端.

我查看了ZeroMQ邮件列表,并且有一条消息说fork()与ZeroMQ的工作方式正交.这是否意味着我无法在分叉子进程中共享我的上下文?如果是这种情况,我如何在多个进程之间共享上下文,同时牢记支持至少256个客户端和仅使用ZeroMQ作为后端的要求?

编辑:清除线程/进程混乱.对于那个很抱歉.

EDIT2:我之所以喜欢分叉线程的原因是我习惯于拥有一个接受传入套接字连接的主进程然后分叉,给孩子提供新的套接字.我不确定如何以线程方式做到这一点(不是很好的练习,但并非完全脱离我的联赛)

EDIT3:所以,开始用线程重写它.我想这是唯一的方法吗?

EDIT4:为了进一步说明,到服务器的传入连接可以是TCP或UDP,我必须处理客户端连接时的类型,所以我不能使用ZeroMQ套接字来监听.

Mat*_*ang 6

上下文共享

在链接的示例代码中共享ZMQ上下文的原因是,server(main())使用inprocsocket与workers(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;
}
Run Code Online (Sandbox Code Playgroud)

处理每个请求的过程

现在谈谈你的要求,每个请求一个流程.最后一个示例代码仅用于说明其用法zmq::proxy,它是为了简化使用ROUTER-DEALER模式的服务器代码而提供的.但它无法满足您的要求.所以,你必须手动实现它.它看起来像另一个例子.区别在于您需要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;
    }
}
Run Code Online (Sandbox Code Playgroud)

建议

最后,我不得不说,除非你的场景非常特殊,否则为一个请求创建一个进程真的太重了.请使用线程,或者考虑异步IO之类的zmq::poll.