Skip to content

Commit ffb6513

Browse files
committed
update port reuse section
1 parent 16af5e4 commit ffb6513

1 file changed

Lines changed: 18 additions & 1 deletion

File tree

content/posts/network-engineering.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,12 +864,29 @@ For example, [BitTorrent], Skype (VoIP), brokerless messaging systems (e.g. [Zer
864864
- Exposed in higher-level languages, e.g. see [Python socket guide]
865865
- A process can open multiple sockets
866866
- A socket can accept multiple connections (as long as they are unique in terms of source and destination IP address and port number)
867-
- Sockets are non-competing consumers of broadcast messages, when creating multiple socket instances on the same host and port number, each socket will receive a copy of the broadcast message sent to that port
867+
- Multiple sockets can bind to the same host and port if they opt in with `SO_REUSEADDR` or `SO_REUSEPORT`; how an incoming message is then shared between them depends on the message type (see port reuse below)
868868
- Besides network sockets, there are other sockets for inter-process communication called Unix Domain sockets (`AF_UNIX` or `AF_LOCAL`) which bypass the network stack
869869

870870
[Python socket guide]: https://docs.python.org/3.13/howto/sockets.html
871871
[socket API]: https://en.wikipedia.org/wiki/Berkeley_sockets
872872

873+
#### Port reuse (`SO_REUSEADDR` and `SO_REUSEPORT`)
874+
875+
By default, only one socket can bind to a given address and port; a second `bind()` fails with `EADDRINUSE`. Two socket options relax this:
876+
877+
- `SO_REUSEADDR`: mainly lets a socket bind to a port still lingering in `TIME_WAIT` (e.g. to restart a server quickly); the other socket need not set the flag
878+
- `SO_REUSEPORT`: lets multiple sockets bind to the exact same address and port, provided every socket sets the flag
879+
880+
Once multiple sockets share a port, how an incoming UDP datagram is delivered depends on its type:
881+
882+
- Broadcast/multicast: non-competing consumers, the kernel delivers a copy to every bound socket; for multicast, to every socket that joined the group
883+
- Unicast: competing consumers, the datagram is delivered to exactly one socket; on Linux, `SO_REUSEPORT` selects the socket via a hash of the packet's 4-tuple (source/destination IP and port), so all packets of one flow reach the same socket; this is a load-balancing mechanism used to spread traffic across worker processes (e.g. nginx); for TCP, the incoming `SYN` is hashed to one listening socket, which then owns the connection
884+
885+
Caveats:
886+
887+
- For multicast addresses, Linux treats `SO_REUSEADDR` and `SO_REUSEPORT` identically; multicast receivers typically use `SO_REUSEADDR` for portability
888+
- BSD/macOS also allow an overlapping bind of the wildcard address (`0.0.0.0`) and a specific IP on the same port (with `SO_REUSEADDR`), delivering each unicast packet to the most specific match; Linux does not allow this wildcard/specific overlap (only two different non-wildcard addresses may share a port)
889+
873890
#### Bind (server) and connect (client)
874891

875892
- A server binds to a particular port to specify where it will listen for incoming client connections (`bind()`), making its service available for clients under a specific address; after binding, it will listen for incoming connection requests (`listen()`)

0 commit comments

Comments
 (0)