I have a parent process which creates 2 server sockets and calls select() on them to wait for new connection. When the connection arrives, a message is sent to a child process (created with fork(), after servers sockets creation, so they are shared).
In this child, calling accept() on the server socket doesn’t work. I got a EAGAIN error (non-blocking socket). Whereas calling accept() in the main process works perfectly.
Of course, I don’t call accept() in the main process at all, I just tested to check if it worked, and it does.
Why can’t I call accept() in a child process after a select() in the parent?
EDIT: The goal here is to create a fixed number of workers (let’s say 8) to handle clients connections, as in the prefork model. These connections will be long-connections, not like HTTP. The goal is to load-balance connections between workers.
To do this, I use a shared memory variable which contains for a worker the number of currently connected clients. I want to “ask” the worker with the lowest number of clients to handle a new connection.
That’s why I do the select() in the parent, and then send a message to a child process, because I want to “choose” which process will handle the new connection.
The server listen on more than one sockets (one for ssl, one without), that’s why I use select() and not directly accept() in children processes, because I can’t accept() on multiple sockets in my children workers.
In fact, the problem was not what I first thought. Here is a recap of what I did to have some basic load-balancing of connections between my worker processes.
select()in an infinite loopaccept()on the server socket (the socket to used between the two is passed in the pipe, so the child knows which one to callaccept()on)The problem was that my parent process told a child to accept the socket and re-enter the loop immediately after, which it runs
select()again. But if the child has not yet accepted the socket,select()returns again, for the same connection. That’s why I got a EAGAIN error, in fact I calledaccept()twice (or more depending on speed — inter process race conditions)!The solution is to wait for the child to answer something on the pipe like “Hey, I accepted the connection, it’s ok!”, and then returns to the
select()loop.This works perfectly fine. The implementation in Python is available here for the curious : https://github.com/thibautd/Kiwi !