SO_REUSEADDR is not SO_REUSEPORT
They get used interchangeably in blog posts and they should not be.
SO_REUSEADDR
Lets a socket bind an address that still has sockets lingering in TIME_WAIT from a
previous process. That is the option that makes a server restartable without waiting out the 2×MSL
timer and seeing EADDRINUSE for a minute. It does not let two live listening
sockets share a port.
SO_REUSEPORT
Does exactly that. Several sockets, each having set the option before binding, share one address and port, and the kernel distributes incoming connections across them by hashing the connection 4-tuple. It is how a multi-process server accepts in parallel without a shared listening socket, and it avoids the thundering herd that a single shared descriptor produces.
The traps
Every socket in the group must set the option — if one forgets, it gets EADDRINUSE
instead of joining. On Linux they must also share an effective UID, which exists specifically so a
different user cannot quietly join a group and steal traffic from a port already in use.
And the load balancing is per-connection, not per-byte. A hash on the 4-tuple distributes connections evenly in aggregate but says nothing about how much work each one carries, so a worker that draws several long-lived heavy connections stays busy while its siblings idle. If your connections are long-lived and unequal, SO_REUSEPORT is not the load balancer you wanted.