跪拜 Guibai
← All articles
Backend · Java · Programmer

One Port, Two Listeners? SO_REUSEPORT vs SO_REUSEADDR, the Real Distinction

By 挖掘狂人 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Rolling deployments break when a second container tries to bind a port already held by its predecessor; knowing when to enable SO_REUSEPORT instead of SO_REUSEADDR prevents these stalls and lets multi-process services scale without a shared-listener lock.

Summary

By default, binding the same IP+port twice fails with EADDRINUSE, which is why most people say one port holds one program. The kernel's conflict check actually hinges on two things: the bound address+port pair and the reuse flags on the socket. SO_REUSEADDR only shortens the TIME_WAIT delay on restart; it never allows two processes to listen simultaneously. SO_REUSEPORT, available since Linux 3.9, permits multiple processes to bind one port, and the kernel distributes inbound connections via a four-tuple hash.

Multi-process servers such as Nginx use SO_REUSEPORT to make each worker hold its own socket, removing the forwarding bottleneck and the thundering herd/lock contention of a shared listener. The trick also enables zero-downtime restarts: new and old processes bind together, then the old one exits gracefully. The failure mode shows up in container rolling releases when the new instance lacks SO_REUSEPORT and cannot bind the host port, stalling the deploy or triggering a rollback. The distinction to remember: TIME_WAIT calls for SO_REUSEADDR, coexistence calls for SO_REUSEPORT.

Takeaways
— Without reuse options, binding the same IP+port twice fails with EADDRINUSE.
— SO_REUSEADDR only allows immediate rebind after TIME_WAIT; it does not permit simultaneous listening.
— SO_REUSEPORT (Linux 3.9+) allows multiple processes to listen on the same port, with the kernel hashing connections to workers.
— Nginx's multi-worker model uses SO_REUSEPORT to avoid a single-process bottleneck and eliminate thundering herd/lock contention.
— SO_REUSEPORT enables zero-downtime restart by letting old and new processes listen together before the old exits.
— Container rolling releases without SO_REUSEPORT fail because the new instance can't bind the host port.
Conclusions

The one-port-one-program rule is a simplification: the kernel's real conflict check is an address+port pair plus socket options, so a second listener can coexist when SO_REUSEPORT is set.

SO_REUSEADDR and SO_REUSEPORT differ by one letter but serve opposite purposes; confusion between them produces the wrong fix for a port conflict.

Container orchestration famously restarts instances without checking socket options, so a missing SO_REUSEPORT becomes a silent release breaker in rolling deployments.

Kernel-side hashing of connections turns SO_REUSEPORT into an implicit load balancer, which is why Nginx workers scale with no user-space coordination.

Concepts & terms
SO_REUSEADDR
A socket option that lets a port be immediately rebound after a connection closes and enters TIME_WAIT, avoiding a restart delay. It does not allow multiple simultaneous listeners.
SO_REUSEPORT
A Linux socket option (since 3.9) that allows multiple processes to bind and listen on the same IP+port; the kernel distributes incoming connections using a hash of the four-tuple.
TIME_WAIT
The TCP state entered by the side that initiates the close, lasting typically 60 seconds, during which the port remains associated with the old connection.
Thundering herd
A situation where multiple processes share a single listening socket and all wake up on a new connection, racing to accept it and wasting CPU; SO_REUSEPORT avoids this by giving each process its own socket.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗