I am implementing a reliable, connection-oriented application over UDP (uni assignment). It is required that the server, after it receives an initial packet from the client and acknowledges it, creates a new worker process. The worker process shall have a socket dedicated to this particular client.
Now I see three ways of implementing this.
listener_socket
, which is bound to the specified port and waits for requests. I could, then, in the child process, connect()
this very socket to the client's address.listener_socket
in the child altogether, then open a brand new socket connection_socket
, bind it to the port and connect it to the client.What I am uncertain about (regarding option 1) is how connecting the listener_socket
to the client affect the original listener_socket
in the parent server. Will it prevent the parent from receiving further messages from other clients? If not, why? Don't they both refer ultimately to the same socket?
As for option 2, this gives me, quite expectedly, "address already in use". Is there some functionality like in routers (i.e. longest matching prefix) that delivers datagrams to the "most fitting" socket? (Well, TCP already does this in accept()
, so it's quite unlikely that this logic could be replicated for UDP.)
Regarding option 3, I think it's quite inefficient, because it implies that I should use a new port for each client.
So could someone please advise on which method to use, or if there is another way I'm not yet aware of? Thanks.
What I am uncertain about (regarding option 1) is how connecting the listener_socket to the client affect the original listener_socket in the parent server. Will it prevent the parent from receiving further messages from other clients?
Yes.
If not, why? Don't they both refer ultimately to the same socket?
Yes, when the parent forks the child, the child receives copies of all the parent's open file descriptors, and these refer to open file descriptions managed by the kernel. Those open file descriptions are thus shared between parent and child. Therefore, if the child connect()
s the socket to a client, then both parent and child will see the effect that
If the socket
sockfd
is of typeSOCK_DGRAM
, then [the specified address] is the address to which datagrams are sent by default, and the only address from which datagrams are received.
(Linux manual page; emphasis added)
As for option 2, this gives me, quite expectedly, "address already in use". Is there some functionality like in routers (i.e. longest matching prefix) that delivers datagrams to the "most fitting" socket?
What would make one socket more fitting than the other? In any case, no. A UDP endpoint is identified by address and port alone.
Regarding option 3, I think it's quite inefficient, because it implies that I should use a new port for each client.
Inefficient relative to what? Yes, your option (3) would require designating a separate port for each client, but you haven't presented any other viable alternatives.
But that's not to say that there aren't other viable alternatives. If you don't want to negotiate a separate port and open a separate socket per client (which is one of the ways that FTP can operate, for example) then you cannot rely on per-client UDP sockets. In that case, all incoming traffic to the service must go to the same socket. But you can have the process receiving messages on that socket dispatch each one to an appropriate cooperating process, based on the message's source address and port. And you should be able to have those processes all send responses via the same socket.
There are numerous ways that the details of such a system could be set up. They all do have the limitation that the one process receiving all the messages could be a bottleneck, but in practice, we're talking about I/O. It is very likely that the main bottleneck would be at the network level, not in the receiving process.