You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已设置SO_REUSEADDR并关闭Socket,为何仍出现Bind地址占用错误?

设置SO_REUSEADDR后仍遇EADDRINUSE:线程中select持有Socket句柄的问题

问题重现

你的代码逻辑是创建带SO_REUSEADDR的Socket监听端口,关闭后尝试重新绑定同端口,却触发以下错误:

`bind': Address already in use - bind(2) for 0.0.0.0:9000 (Errno::EADDRINUSE)

核心原因

问题出在run方法里的子线程IO.select调用:

  • 第一个ServerWrapper实例启动的子线程中,IO.select [@sock]会持续阻塞并持有Socket对象的引用。
  • 主线程调用@a.close关闭Socket后,子线程的select仍在阻塞,Socket对象的引用并未完全释放(子线程还在占用它)。在类UNIX系统中,Socket作为文件描述符,只有当所有引用它的IO对象都被销毁后,内核才会彻底回收端口资源。
  • SO_REUSEADDR的作用是允许复用处于TIME_WAIT状态的端口,或者允许多个进程/线程绑定同端口(用于多进程监听),但它无法解决“仍被活跃线程引用的Socket”占用端口的问题。

解决方案

要解决这个问题,必须让子线程在Socket关闭后及时退出,释放Socket引用。以下两种方法都可行:

方法1:捕获Socket关闭时的异常退出线程

修改run方法中的子线程代码,捕获EBADF异常(Socket关闭后select会触发此错误):

class ServerWrapper
    def run
        @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
        @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
        @sock.bind(Socket.sockaddr_in(9000, '0.0.0.0'))
        @sock.listen(1024)

        Thread.new do
            begin
                IO.select [@sock], nil, nil, nil
            rescue Errno::EBADF
                # Socket已关闭,线程正常退出
            end
        end.join
    end

    def close
        @sock.close
    end
end

调用close后,select会触发异常,子线程退出,Socket的所有引用被释放,内核回收端口,第二次绑定即可成功。

方法2:添加停止标志实现优雅退出

给ServerWrapper添加停止标志,让select通过超时定期检查标志:

class ServerWrapper
    def initialize
        @stop = false
    end

    def run
        @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
        @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
        @sock.bind(Socket.sockaddr_in(9000, '0.0.0.0'))
        @sock.listen(1024)

        Thread.new do
            until @stop
                # 每1秒检查一次停止状态
                ready = IO.select([@sock], nil, nil, 1)
                break if @stop
                # 此处可添加连接处理逻辑
            end
        end.join
    end

    def close
        @stop = true
        @sock.close
    end
end

这种方式更灵活,适合需要优雅关闭服务的场景,线程会在下一次检查标志时退出,释放Socket资源。

内容的提问来源于stack exchange,提问作者eskaes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:13:14