我在golang中有一个设置,它基本上从操作系统获得一个空闲端口,然后在其上启动一个http服务器。它开始出现端口注册失败的随机错误。我把它简化为以下程序,在抓住一些空闲端口后似乎出错了。它发生得非常随机,并且没有真正的进程在端口上运行它出错。对我来说,为什么这有误,对我一点都没有意义。任何帮助将不胜感激。
计划的输出:
..
..
58479个
..
..
58867个
58868个
58869个
..
很好! 58867个
很好! 58868个
很好! 58869个
..
..
..
2015/04/28 09:05:09绑定端口时出错:listen tcp:58479:bind:地址已在使用中
我确保检查出来的免费端口从未重复过。
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)
}()
}
}
答案 0 :(得分:6)
你所做的是检查端口是否在某一点是免费的,然后你尝试使用它,这是基于它过去是免费的。这不会起作用。
会发生什么:在for循环的每次迭代中,您都会生成一个端口号,并确保它是免费的。然后,您生成一个例程,意图使用此端口(已经释放回可用端口池)。你不知道什么时候开始运行。它可能会在主程序(for循环)刚刚生成另一个自由端口时被激活 - 也许是同一个自由端口?或者也许另一个进程同时采用了这个端口。基本上你可以在一个端口上拥有竞争条件。
经过多次研究后发现:
但有一点需要注意。只要本地+远程对是唯一的,两个不同的套接字就可以绑定到同一个ip +端口。我曾经写过一篇关于它的response。因此,当我用:0
创建听众时,我能够得到一个"碰撞&#34 ;;由netstat -an
证实:
10.0.1.11.65245 *.* LISTEN
10.0.1.11.65245 17.143.164.101.5223 ESTABLISHED
现在,问题是如果要显式绑定套接字正在使用的端口,这是不可能的。可能是因为您只能指定本地地址,并且在调用listen或connect之前不会知道远程地址(我们现在谈的是系统调用,而不是Go界面)。换句话说,当您未指定端口时,OS有更广泛的选择。因此,如果它发生了一个也被另一个套接字使用的本地地址,你就无法手动绑定它。
如何解决它:
正如我在评论中提到的那样,您的服务器进程应使用:0
表示法,以便能够从操作系统中选择可用资源。一旦它正在倾听,地址应该通知感兴趣的进程。例如,您可以通过文件或标准输出来执行此操作。
答案 1 :(得分:-1)
可能您之前在此端口上运行或调试了一个应用程序,并且它没有完全关闭。该进程可能仍在您的系统内存中。完全终止该进程,以及可能潜伏在阴影中的任何其他网络守护进程,然后再次尝试运行您的应用程序。
如果您还没有检查过,您可以使用(如果使用 Linux)dotnet publish
、top
或任何 GUI 系统监视器,例如 Windows 的 htop
、Gnome3 的 {{ 1}} 或 KDE 的 Task Manager
来搜索违规进程。
例如,我观察到 Visual Studio Code 的调试器/运行器实用程序 (F5/Ctrl+F5) 并不总是清理进程,尤其是当您按 F5 太快并且旧的调试器没有关闭时。< /p>