I'm writing a point-to-point message queue system, and it has to be able to operate over UDP. I could arbitrarily pick one side or the other to be the "server" but it doesn't seem quite right since both ends are sending and receiving the same type of data from the other.
Is it possible to bind() and connect() both ends so that they send/receive only from each other? That seems like a nicely symmetric way to do it.
I'd look at it more from the idea of what UDP is providing. UDP is an 8 byte header which adds 2 byte send and receive ports (4 bytes total). These ports interact with Berkeley Sockets to provide your traditional socket interface. I.e. you can't bind to an address without a port or vice-versa.
Typically when you send a UDP packet the receive side port (source) is ephemeral and the send side port (destination) is your destination port on the remote computer. You can defeat this default behavior by binding first and then connecting. Now your source port and destination port would be the same so long as the same ports are free on both computers.
In general this behavior (let's call it port hijacking) is frowned upon. This is because you have just limited your send side to only being able to send from one process, as opposed to working within the ephemeral model which dynamically allocates send side source ports.
Incidentally, the other four bytes of an eight byte UDP payload, length and CRC are pretty much totally useless as they are already provided in the IP packet and a UDP header is fixed length. Like come on people, computers are pretty good at doing a little subtraction.
There is a problem in your code:
By using AF_UNSPEC and SOCK_DGRAM only, you gets a list of all the possible addrs. So, when you call socket, the address you are using might not be your expected UDP one. You should use
instead to make sure the addrinfo you are retrieving is what you wanted.
In another word, the socket you created may not be an UDP socket, and that is the reason why it does not work.
Really the key is
connect()
:If you are c/c++ lover, you may try route_io
It is simple to use, create a instance to accept different port routing to your function.
Example :
Here's a program that demonstrates how to bind() and connect() on the same UDP socket to a specific set of source and destination ports respectively. The program can be compiled on any Linux machine and has the following usage:
I tested this code opening two terminals. You should be able to send a message to the destination node and receive messages from it.
In terminal 1 run
In terminal 2 run
Even though I've tested it on a single machine I think it should also work on two different machines once you've setup the correct firewall settings
Here's a description of the flow:
Hello from the distant future which is the year 2018, to the year 2012.
There's, in fact, a reason behind
connect()
ing an UDP socket in practice (though blessed POSIX doesn't in theory require you to).An ordinary UDP socket doesn't know anything about its future destinations, so it performs a route lookup each time
sendmsg()
is called.However, if
connect()
is called beforehand with a particular remote receiver's IP and port, the operating system kernel will be able to write down the reference to the route and assign it to the socket, making it significantly faster to send a message if subsequentsendmsg()
calls do not specify a receiver (otherwise the previous setting would be ignored), choosing the default one instead.Look at the lines
1070
through1171
:Until Linux kernel 4.18, this feature had been mostly limited to the IPv4 address family only. However, since 4.18-rc4 (and hopefully Linux kernel release 4.18 as well), it's fully functional with IPv6 sockets as well.
It may be a source of a serious performance benefit, though it will heavily depend on the OS you're using. At least, if you're using Linux and don't use the socket for multiple remote handlers, you should give it a try.