I'm writing a forking chat server in C++, with each incoming client being its own process. The server-client interactions are done though normal sockets with ZeroMQ sockets handling message queuing and IPC. The basic problem is that there when the server forks to accommodate the new client, the client's process has a copy of the context (which is what fork does, right?), so when it binds sockets with the context, none of the other clients are aware of the socket. Long story short: how do I get each client thread to have the same context so that they can talk to each other through ZeroMQ?
I've looked at various ways to share the context between processes, and so far I'm found only this one. The problem with that is 1) it uses a thread pool, and from what I understand from what's written there, only 5 threads are created; this server is needs to support at least 256 and thus will have at least that many threads, and 2) it uses ZeroMQ for both talking to clients and for backend tasks; I'm limited to using ZeroMQ for backend only.
I've looked at the ZeroMQ mailing list and one message said that fork() is orthogonal to how ZeroMQ works. Does this mean that I can't share my context across forked child processes? If that's the case, how do I share the context across multiple processes while keeping in mind the requirement of supporting at least 256 clients and using ZeroMQ for only backend?
EDIT: Cleared up the thread/process confusion. Sorry about that.
EDIT2: The reason why I'm also favoring forking over threads is that I'm used to having a main process that accepts an incoming socket connection then forks, giving the new socket to the child. I'm not sure how to do that in a threading fashion (not really well-practiced, but not totally out of my league)
EDIT3: So, starting to rewrite this with threads. I guess this is the only way?
EDIT4: For further clarification, incoming connections to the server can be either TCP or UDP and I have to handle which type it is when the client connects, so I can't use a ZeroMQ socket to listen in.
The reason to share ZMQ context in the example code from your link is, that the server(main()) uses inproc socket to communicate with workers(worker_routine()). Inproc sockets cannot communicate with each other unless they are created from the same ZMQ context, even they settle in the same process. In your case, I think it's not necessary to share it since no inproc sockets are supposed to be used. So, your code might look like:
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;
}
And now to talk about your requirement, one process per request. The last example code is just intended to illustrate the usage of zmq::proxy, which is provided to simplify the server code with ROUTER-DEALER pattern. But it can't fulfill your requirement. So, you have to implement it manually. It just looks like another example. The difference is that you need to invoke fork() when frontend socket is readable and put the while loop into sub process.
if (items[0].revents & ZMQ_POLLIN) {
if (fork() == 0) {
// sub process runs here
while (1) {
// forward frames here
}
// sub process ends here
return 0;
}
}
At the end, I have to say, it's too much heavy to create a process for one request exactly unless your scenario is really special. Please use thread, or consider the asynchronous IO like zmq::poll.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With