猿问

即使端口上没有运行任何内容,但绑定地址已在使用中的 golang 错误

我在 golang 中有一个设置,它基本上从操作系统获得一个免费端口,然后在它上面启动一个 http 服务器。它开始出现端口注册失败的随机错误。我将其简化为以下程序,该程序在获取一些空闲端口后似乎出错。它非常随机地发生,并且在它出错的端口上没有运行真正的进程。为什么这必须出错对我来说根本没有意义。任何帮助,将不胜感激。


程序的输出:


..

..

58479

..

..

58867

58868

58869

..

必然好!58867

绑定好!58868

绑定好!58869

..

..

..

同时绑定端口2015年4月28日9时05分09秒错误:已在使用地址:听TCP:58479:绑定


我确保检查出来的自由端口从未重复。


package main


 import (

    "net"

    "net/http"

    "log"

    "fmt"

)


func main() {


    for {

        l, _ := net.Listen("tcp", ":0")

        var port = l.Addr().String()[5:]

        l.Close()

        fmt.Println(port)

        go func() {

                l1, err := net.Listen("tcp", ":"+port)

                if (err != nil) {

                    log.Fatal("Error while binding port: ", err.Error())

                } else {

                    fmt.Println("bound well! ", port)

                }

                http.Serve(l1, nil)

            }()

    }

}


拉风的咖菲猫
浏览 197回答 2
2回答

绝地无双

您所做的是检查端口是否在某一时刻空闲,然后根据过去它是空闲的事实尝试使用它。这是行不通的。会发生什么:在 for 循环的每次迭代中,您都会生成一个端口号并确保它是空闲的。然后您生成一个打算使用这个端口的例程(它已经被释放回空闲端口池)。你真的不知道这个例程什么时候开始。它可能在主例程(for 循环)刚刚生成另一个空闲端口时被激活——也许又是同一个?或者也许另一个进程同时占用了这个端口。本质上,您可以在单个端口上存在竞争条件。经过更多的研究:不过有一个小警告。只要本地+远程对是唯一的,两个不同的套接字就可以绑定到同一个ip+端口。因此,当我创建侦听器时,:0我能够获得“碰撞”;证明netstat -an:10.0.1.11.65245        *.*                    LISTEN 10.0.1.11.65245        17.143.164.101.5223    ESTABLISHED现在,问题是如果您想显式绑定正在使用的端口的套接字,这是不可能的。可能是因为您只能指定本地地址,而在调用侦听或连接之前不会知道远程地址(我们现在谈论的是系统调用,而不是 Go 接口)。换句话说,当您不指定端口时,操作系统有更广泛的选择。因此,如果发生这种情况,您的本地地址也正被另一个套接字使用,您将无法手动绑定到它。如何解决:正如我在评论中提到的,您的服务器进程应该使用:0符号,以便能够从操作系统中选择可用资源。一旦它开始侦听,就应该向感兴趣的进程宣布地址。例如,您可以通过文件或标准输出来实现。

隔江千里

可能您之前在此端口上运行或调试应用程序,并且它没有完全关闭。该进程可能仍在您的系统内存中。完全终止该进程,以及可能潜伏在阴影中的任何其他网络守护进程,然后再次尝试运行您的应用程序。如果您还没有检查过这一点,您可以使用(如果使用 Linux)top、htop或任何 GUI 系统监视器,如 Windows' Task Manager、Gnome3System Monitor或 KDE'sKSysGuard来搜索有问题的进程。例如,我观察到 Visual Studio Code 的调试器/运行器实用程序 (F5/Ctrl+F5) 并不总是清理进程,特别是如果您按 F5 太快并且旧的调试器没有关闭。
随时随地看视频慕课网APP

相关分类

Go
我要回答