I come from a C background and from my understanding, UDP is a connection-less protocol which, I assume, means that packets can be sent without making a connection first. However, as I have gotten into Go and started writing networking code, I realised that Go's UDP writer dials a host before sending packets to it. Why is that?
UDP is connectionless, at least in principal (implementations vary). But there's still an implementation detail to worry about: to send a UDP packet (datagram) from "me" (my IP host and port addresses) to "you" (your IP host and port addresses), I must, at the least, specify your IP-and-port. The same goes in reverse if and when you want to send a datagram to me.
Depending on the underlying OS, you or I may be able to do this with a sendto
system-call. That is, we start with a socket
system call, then use a sendto
system call to fire-and-forget: the datagram goes off, or doesn't, and we never bother to see what happens next. The sendto
call takes a destination address, which for TCP or UDP, supplies the IP address and port.
Or, we may use a socket
system call, followed by an optional bind
system call, followed by a connect
system call.1 The bind
, if we do it, establishes our local port (and maybe IP address, if we have more than one) and the connect
establishes our destination IP address and port. Now we can send packets with write
or send
system calls.
(Some systems add sendmsg
and other such calls, which are generally supersets of all of the above and therefore can be used without a preliminary connect
. But all systems that support TCP have the concept of creating a network connection and bind-and-or-connect-ing and then writing data.)
One least-common-denominator setup, which is also pretty useful, is to assume that you'll specify your remote peer address at the time you want to create a network connection. To do that in Go, use Dial
. Even if your underlying system has, say, only raw IP sockets, the library could build UDP atop those and provide the Dial
interface, and that would then still work in Go.
1Ideally, this probably should have been an "establish peer information" system call, providing both local and remote addressing information, plus any optional flags. Omitting a remote specifier would mean "listen to all incoming connections from everyone". That would have eliminated the need for the SO_REUSEADDR
flag, which exists just because it's otherwise impossible to distinguish between a bind
that comes before a connect
, or a bind
that comes before a listen
. But it's a little late to fix 4.2BSD now. 😀