V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
c00WKmdje2wZLrSI
V2EX  ›  Go 编程语言

求助, go 端口占用的问题

  •  
  •   c00WKmdje2wZLrSI · 336 天前 · 2192 次点击
    这是一个创建于 336 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境:ubuntu22.04 go1.20

    代码类似于

    go func() {
    		//开启 websocket 监听
    		http.HandleFunc("/", s.handler)
    		err := http.ListenAndServe("0.0.0.0:9999", nil)
    		if err != nil {
    			logger.Log.Fatal(fmt.Sprintf("err=%v", err))
    		}
    	}()
    

    但是有时候启动会报错,显示err=listen tcp 0.0.0.0:9999: bind: address already in use 然而我使用netstat -tuln |grep 9999时,却显示这个端口没被占用

    于是我写一个脚本

    #!/bin/bash
    
    while true; do
      netstat -tuln |grep 9999
      sleep 0.1
    done
    

    一直开着,再写一个守护脚本当 go 进程结束时自动重启 然后我发现 go 进程因为端口占用问题已经重启了几十次,但是端口扫描的脚本却一次显示端口被占用的情况都没有

    但是当我过几个小时再次重启 go 进程时,端口占用问题又消失了 这到底是怎么一回事,而且这情况不是必现的,是偶尔会出现

    33 条回复    2023-12-18 20:34:17 +08:00
    c00WKmdje2wZLrSI
        1
    c00WKmdje2wZLrSI  
    OP
       336 天前
    各位大哥有没有解决的思路可以说一说
    misaka19000
        2
    misaka19000  
       336 天前 via Android
    写个其它语言的代码看看能不能监听这个端口
    daniel8642
        3
    daniel8642  
       336 天前
    0.0.0.0:9999
    可以试试填写一下需要绑定到的网卡 ip 地址。
    之前在 wsl2 上出现绑定之后访问不了,就是通过填写 ip 解决的。
    imherer
        4
    imherer  
       336 天前
    会不会是你这个函数被多次调用了?
    c00WKmdje2wZLrSI
        5
    c00WKmdje2wZLrSI  
    OP
       336 天前
    @daniel8642
    @imherer

    主要是这个是偶现的,而且我端口扫描脚本显示进程启动时它所需要的端口没被占用
    sky96111
        6
    sky96111  
       336 天前 via Android
    https://zhaoji.wang/solve-the-problem-of-windows-10-ports-being-randomly-reserved-occupied-by-hyper-v/
    看看是不是这个问题。我经常遇到
    c00WKmdje2wZLrSI
        7
    c00WKmdje2wZLrSI  
    OP
       336 天前
    @sky96111 不是,我是腾讯云的服务器,ubuntu22.04, 而且主要是我扫描了端口,显示未占用
    zhoulq7
        8
    zhoulq7  
       336 天前
    如果用了 iptables 做的端口流量转发是不能通过 netstat 查到这个被占用的端口的
    sky96111
        9
    sky96111  
       336 天前 via Android
    @c00WKmdje2wZLrSI Linux 啊,那你用 lsof -i :端口号查一下。被内核占用的端口直接是看不到的
    barathrum
        10
    barathrum  
       336 天前
    可能是 socket 还没回收,关应用的时候如果正好有链接要等 60 秒 保证被回收,没有链接的话就能直接用了。
    ss 的时候去掉 l 再看看可能发现有正在关闭状态的链接。
    c00WKmdje2wZLrSI
        11
    c00WKmdje2wZLrSI  
    OP
       336 天前
    @zhoulq7 systemctl status firewalld 和 systemctl status firewalld 显示没这两个软件
    c00WKmdje2wZLrSI
        12
    c00WKmdje2wZLrSI  
    OP
       336 天前
    @barathrum 我换了端口后,扫描新端口没被占用,但是新端口第一次启动也有几率出现说端口被占用
    longbowape
        13
    longbowape  
       336 天前
    需要给端口设置 SO_REUSEADDR ,否则即使进程推出了也会显示一段时间的被占用。
    Pythoner666666
        14
    Pythoner666666  
       336 天前
    云服务器有一些 厂商自带的扫描或者监控软件 他们可能是定时启动 端口也是 9999 ,所以可能刚好跟你冲突了。仅提供一个思路,不一定对哈。
    barathrum
        15
    barathrum  
       336 天前
    你的监控脚本换一下参数,比如 netstat -neoap 啥的,端口不一定是 listen 的。
    lsk569937453
        16
    lsk569937453  
       336 天前
    https://groups.google.com/g/golang-nuts/c/nUMvimzSZvk
    不知道是不是和这个有关系,用 go build 后的二进制包启动,而不是用 go run 启动进程。
    liarsa
        17
    liarsa  
       336 天前
    我也碰到过,但没细研究,过一会它自己就好了
    c00WKmdje2wZLrSI
        18
    c00WKmdje2wZLrSI  
    OP
       336 天前
    @lsk569937453 我使用的就是 go build 的二进制包启动的
    pkoukk
        19
    pkoukk  
       336 天前
    简单啊,你测试下换几个端口,如果还有问题就是你代码写的问题
    如果没问题就是你环境的问题
    mangoDB
        20
    mangoDB  
       336 天前
    netstat -n | grep TIME_WAIT
    julyclyde
        21
    julyclyde  
       336 天前
    @zhoulq7 iptables 转发的情况并不会发生冲突
    只是很单纯的无法生效而已
    julyclyde
        22
    julyclyde  
       336 天前
    if err != nil {
    logger.Log.Fatal(fmt.Sprintf("err=%v", err))
    请你在这里运行一下 netstat -anp
    这里应该是能抓到事故现场的
    }
    pennai
        23
    pennai  
       335 天前
    你换个端口号,如果换了端口号还是同样的报错,看看是不是你写的代码有问题,这个函数跑了多次
    lifei6671
        24
    lifei6671  
       334 天前
    你可以尝试,只启动端口,不建立客户端连接,这种情况下是不是就不存在端口被占用的情况了。
    如果是的话,那么可能是因为服务器端主动断开连接后,这个服务器监听的端口需要等待 2MSL 周期才能再使用。
    这个时间会很短,估计在你执行 netstat 命令的时候端口已经释放了。
    可以尝试缩短 TIME_WAIT 的时间,或者在关闭服务器之前,将所有客户端都 close 了再关闭服务端。
    c00WKmdje2wZLrSI
        25
    c00WKmdje2wZLrSI  
    OP
       333 天前
    @julyclyde 感谢,抓到事故现场了,的确有进程监听了那个端口
    c00WKmdje2wZLrSI
        26
    c00WKmdje2wZLrSI  
    OP
       333 天前
    @julyclyde 说错了,是有进程使用那个端口进行非监听状态的连接,导致我使用 netstat -tuln 找不到进程,而使用 netstat -anp 找到了
    julyclyde
        27
    julyclyde  
       333 天前
    @c00WKmdje2wZLrSI 你之前没有加-a 吧
    -a 就是搜 LISTEN 的

    没明白你说的“非监听状态”是啥意思啊
    c00WKmdje2wZLrSI
        28
    c00WKmdje2wZLrSI  
    OP
       333 天前
    @julyclyde chatgpt 和我说的,我也不知道那是啥意思
    ```
    netstat -tuln | grep 9999 和 netstat -anp | grep 9999 是两个不同的命令,它们的区别在于使用的参数和显示的信息。

    netstat -tuln 命令用于显示所有 TCP 和 UDP 监听的端口。它的参数含义如下:

    -t:仅显示 TCP 协议相关的连接。
    -u:仅显示 UDP 协议相关的连接。
    -l:仅显示监听状态的连接。
    -n:以数字形式显示 IP 地址和端口号。
    netstat -anp 命令用于显示所有活动的 TCP 和 UDP 连接。它的参数含义如下:

    -a:显示所有连接,包括监听和非监听状态的连接。
    -n:以数字形式显示 IP 地址和端口号。
    -p:显示与连接关联的进程信息。
    根据你的描述,可能是因为在使用 netstat -tuln | grep 9999 命令时,没有找到与端口 9999 相关的监听状态的连接,所以没有显示结果。而使用 netstat -anp | grep 9999 命令时,显示了所有活动的连接,包括监听和非监听状态的连接,因此能够发现端口监听情况。
    ```
    julyclyde
        29
    julyclyde  
       333 天前
    @c00WKmdje2wZLrSI GPT 说的和 manpage 也没啥区别啊

    那你抓到的现场,它是 ESTABLISHED 还是 LISTEN 呢?
    c00WKmdje2wZLrSI
        30
    c00WKmdje2wZLrSI  
    OP
       333 天前
    @julyclyde ESTABLISHED
    julyclyde
        31
    julyclyde  
       333 天前
    @c00WKmdje2wZLrSI 那我觉得 GPT 肯定不会告诉你 ip_local_port_range 这个词
    c00WKmdje2wZLrSI
        32
    c00WKmdje2wZLrSI  
    OP
       333 天前
    @julyclyde 是的,不会,而且我发现是另外一个进程和 mysql 通信时临时占用了端口,并且还是随机占用端口,一段时间后又释放了端口,不知道该怎么设置来避免
    julyclyde
        33
    julyclyde  
       333 天前
    @c00WKmdje2wZLrSI 那你就搜搜这个词
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2804 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:49 · PVG 20:49 · LAX 04:49 · JFK 07:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.