In typical UDP programming, unconnected sockets are used both in the client and server sides.
sendto()
is used to specify a peer address while recvfrom()
is utilized to receive a peer address.
In the quic
library in Haskell, I used connected sockets for performance reasons.
If a connected socket is created for a QUIC connection, recv()
can receive data from a specific peer. This means that data is dispatched in the kernel. To understand UDP connection in detail, please read Accepting UDP connections.
As I described in Implementing QUIC in Haskell, I found a drawback of this approach. When a client migrates networks, for instance, from a cell phone network to WiFi, the quic
library has to detect the new network interface gets available. It is hard to implement a cross-platform scheme for this detection. So, I added another mode to use a unconnected socket and sendto()
for clients.
One of my colleagues told me a drawback of servers recently. The quic
library assumes that NAT rebindings do not occur during a connection creation. Once a QUIC connection is created, a server can handle NAT rebidings. What he found is there are NAT boxes which change ports very quickly.
I had to admit that the connected socket approach is not feasible. Therefore, all code for connected sockets were removed and a new approach with unconnected sockets is introduced. Note that sendmsg()
and recvmsg()
are used instead of sendto()
and recvfrom()
to work with load balancers of DSR (Direct Server Return).
The quic
library version 0.2.0 or later provide this new architecture.