so_reuseaddr必须在bind前设置,否则服务器重启时因time_wait状态导致“address already in use”错误;它允许新socket复用处于time_wait的端口,但不允许多进程同时监听同一端口。

SO_REUSEADDR 必须设,否则重启就失败
服务器进程被 kill -9 或崩溃后,绑定的端口会卡在 TIME_WAIT 状态(默认 60 秒),此时立刻重启会报 Address already in use。设 SO_REUSEADDR 就是为解决这个——它允许新 socket 绑定到处于 TIME_WAIT 的旧地址+端口组合。
关键点:
- 必须在
bind()之前调用setsockopt() - 参数值传整型
1,类型是int,不能传指针或字节序转换后的值 - 所有 TCP 服务端程序都该加,不管是否多进程
- 它不允许多个监听 socket 同时 bind 成功;第二个
bind()仍会失败
示例片段:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int reuse = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
struct sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); // 这里才 bind
SO_REUSEPORT 才能真正多进程监听同一端口
想让多个 worker 进程(比如 Nginx 的 master + 多个 worker)各自 socket()、bind()、listen() 同一个 127.0.0.1:8080,必须用 SO_REUSEPORT。内核会按四元组哈希分发新连接,实现无锁负载均衡。
但要注意:
- Linux 内核需 ≥ 3.9(用
uname -r检查) - 所有参与复用的进程,都必须显式设置
SO_REUSEPORT;漏一个,整个复用就失效 - 所有进程 effective user ID 必须相同,否则
bind()返回EACCES - Windows 不支持
SO_REUSEPORT,#define SO_REUSEPORT SO_REUSEADDR是伪实现,最后一个绑定者独占收包
错误写法(只设一个进程):
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
// 进程 A 设了 SO_REUSEPORT → bind 成功 // 进程 B 没设 → bind 失败,报 EADDRINUSE
两个选项可以同时启用,但语义完全独立
SO_REUSEADDR 和 SO_REUSEPORT 不是互斥关系,而是正交功能:前者管“时间维度”的端口重用(绕过 TIME_WAIT),后者管“空间维度”的并发绑定(多进程共享端口)。生产环境建议两者都设。
常见误操作:
- 以为开了
SO_REUSEADDR就能多进程 bind → 实际上第二个进程仍会bind()失败 - 在旧内核(如 CentOS 6 默认 2.6.32)上强行用
SO_REUSEPORT→setsockopt()返回 -1,errno == EINVAL - 没检查返回值,
setsockopt()失败后继续bind()→ 表面运行正常,实则复用未生效
安全起见,可封装成统一函数:
void enable_socket_reuse(int sockfd) {
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#ifdef __linux__
if (kernel_version >= KERNEL_3_9) {
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
}
#endif
}
验证是否生效:用 lsof 或 ss 看监听状态
设完之后别光信代码,得看系统实际行为。启动多个进程后执行:
ss -tlnp | grep ':8080' # 或 lsof -i :8080
如果看到多个 LISTEN 行,且 PID 不同,说明 SO_REUSEPORT 生效;如果只有一行,但重启很快成功,说明 SO_REUSEADDR 起作用了。
容易忽略的一点:UDP 和 TCP 对这两个选项的行为一致,但跨协议(TCP vs UDP)绑定同一端口不受影响——TCP 的 8080 和 UDP 的 8080 本来就是两个独立端口空间。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










