网页 综合 更新时间 2026-11-13 15:01:43

同一个端口能不能被两个程序同时监听? - codigger - 博客园

自动蜘蛛 www.cnblogs.com 正文约 1450 字
同一个端口能不能被两个程序同时监听? - codigger - 博客园
前几天有同事问我一个挺基础的问题:同一个端口,能不能被两个程序同时监听?
他想都没想就给出了答案:"不能啊,一个端口只能被一个程序占用。" 这话其实没错,我以前也是这么答的。但紧接着他问了我第二个问题,把我问住了:那 Nginx 开好几个 worker 进程,为什么大家都监听着 80 端口,跑得还好好的?
答案显然不是简单的能或不能。这里头藏着一套套接字绑定的规则,值得认真捋一遍。
先说个多数人没有的清晰认知。我们对端口的印象往往就是一个粗糙的模型:"一个端口对应一个程序"。但内核的判定比这精细得多。
程序监听端口,本质上是做了一次 bind 操作,把自己绑到某个 IP + 某个端口的组合上。内核里维护着一张绑定关系表,记录哪些地址和端口已经被占,被哪个套接字占着。
默认规则很直接:一个端口已经被绑定为监听状态了,另一个程序再想绑同样的地址和端口,内核直接返回错误,提示地址已在使用。也就是我们见得最多的"端口被占用",Linux 上对应 EADDRINUSE 错误码。
没有设置任何复用选项时,内核严格保证同一地址加端口组合的唯一性 —— 想想也对,如果两条规则都不拦,内核根本没法决定一个连接该交给谁。
内核设计者当然知道死规则会带来麻烦,所以提供了开关。这里有两个选项,名字像,职责完全不同,我以前就混过。
它解决的问题是端口处在等待回收状态时没法立即重新绑定。 TCP 连接关闭时,主动关闭的一方要经历 TIME_WAIT 状态,通常得等个 60 秒左右,这段时间端口实际上还挂着旧连接的残留。没有它,你刚 kill 掉服务马上重启,就会撞上 "端口被占用",只能干等一两分钟。所以这个选项几乎是生产环境网络编程的标配。
不过要说清楚:SO_REUSEADDR 只是让你重启快一点,它并不允许两个进程同时监听同一个端口。真正干这事儿的是第二个。
开了它,多个进程可以真正同时绑定并监听同一个端口。 这时候内核的行为变了:到达这个端口的连接,内核按哈希规则(通常基于源地址和源端口的四元组)分发给各个监听进程。相当于内核层面自带了一层负载均衡。
高性能的网络服务经常用多进程模型,比如 Nginx 的 worker。每个进程开端口复用去监听同一个端口,好处有两个:
容器化场景下还有个巧妙的用法:零停机重启。新旧两套服务进程先同时监听同一端口,新进程就绪后再让旧的优雅退出,用户侧完全感知不到。
顺带提一个容易翻车的地方:如果没开复用选项就启动两个服务实例,第二个会直接启动失败。
这种事在容器滚动发布时最常见。新版本容器和旧版本短暂共存,两边都想绑同一个宿主机端口,代码或配置里又没设置 SO_REUSEPORT,新容器就起不来了,发布卡住甚至触发回滚。
回到开头那个问题,现在可以完整地回答了。
默认情况下,同一个地址加端口的组合只能被一个程序绑定监听,重复绑定报 "端口被占用"。 开了 SO_REUSEPORT 之后,多个进程可以同时监听同一个端口,内核会对入站连接做哈希分发,这种做法常见于多进程的高性能服务。
另外注意:SO_REUSEADDR 和 SO_REUSEPORT 是两回事,一个管重启快,一个管多进程共享监听。
说到底,判断监听是否冲突,本质就是看绑定的地址加端口组合,再加上有没有设置复用标志。能把这几个层次分清楚,说明你不光记住了结论,内核里那套机制你是真懂 —— 毕竟踩过容器发布端口冲突的坑,和只是背过一条 "端口只能被一个程序占用",完全是两种水平。
访问原文 返回搜索 https://www.cnblogs.com/codigger/p/23519349
本页为82搜索生成的网页快照,内容来自站内索引;演示数据的原文链接仅作示例。