I have some Perl code that listens on an array of sockets via select for a request, and then some other routine sends out a response after significant processing.
Now the question is (assuming I have the peer's address in $dest):
How should I select the "correct" socket to use for sending the response to $dest?
Should I blindly use the socket where the request was received on, or should I try to duplicate routing logic to find the "best" socket, considering the address each socket is bound to, comparing it with $dest somehow?
I have little ideas how to do the latter, unfortunately.
I forgot one special case (that actually triggered the problem in the existing code):
It is possible that the array of listening sockets is reduced by the socket that received the request before the response can be set; thus it seems I need to implement the second alternative.
You should use the same socket for all communication with a given peer.
There are times where it doesn't matter, but there are times that it does.
That said, you probably should only have socket.
When you receive from a UDP socket, you are give the the address and port from which the socket originated.[1] This allows one socket to communicate with many other sockets.
For example,
Say the server S's socket is 0.0.0.0:1111 and one of its IP addresses is 1.1.1.1.
Say client A's socket is 0.0.0.0:2222 and say it uses IP address 2.2.2.2 to reach 1.1.1.1.
Say client B's socket is 0.0.0.0:3333 and say it uses IP address 3.3.3.3 to reach 1.1.1.1.
When the server calls
recv, it will return either 2.2.2.2:2222 or 3.3.3.3:3333 (in a "packed" form) depending on whether A or B sent the message. This allows the server to know who is communicating with it, and what address to use when replying.In the TCP world, the server might keep per-connection data in a hash keyed by client socket (the socket returned by
accept). But in the UDP world, a similar server could keep per-connection data in a hash keyed by the string returned byrecv.This illustrates one reason why it's important to always use the same socket to send and receive message. If you start sending from different sockets, this hash lookup would fail.
There is one situation in which you'd want multiple sockets, and that's when you want to listen to some but not all network interfaces. For example, you might want to listen to the loopback adapter (127.0.0.1) and the virtual adapter used for communicating with a VM (x.x.x.x), but not to the wifi adapter (y.y.y.y) or the ethernet adapter (z.z.z.z)
A socket can either listen to all interfaces (by being bound to IPADDR_ANY (0.0.0.0), which is the default), or one interface. So listening (only) two interfaces requires having one socket bound to one of the interfaces (127.0.0.1) and another socket bound to the other (x.x.x.x).
Here, it's critical that you use the correct socket. Messages sent from the socket bound to the loopback adapter won't reach the VM, and messages sent from the socket bound to the VM's adapter won't reach the loopback adapter.