Ail*_*ila 4 port tcp go httpserver
我在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)
}()
}
}
Run Code Online (Sandbox Code Playgroud)
小智 11
首先我检查端口:
$ lsof -i :8080
Run Code Online (Sandbox Code Playgroud)
结果是:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
WeChat 1527 wonz 241u IPv4 0xbfe135d7b32e86f1 0t0 TCP wonzdembp:63849->116.128.133.101:http-alt (ESTABLISHED)
__debug_b 41009 wonz 4u IPv6 0xbfe135e149b1e659 0t0 TCP *:http-alt (LISTEN)
Run Code Online (Sandbox Code Playgroud)
所以我杀死了PID:
$ kill 41009
Run Code Online (Sandbox Code Playgroud)
然后就可以了。
你做的是检查端口是否在某一点是免费的,然后你尝试使用它是基于它过去是免费的事实.这不会起作用.
会发生什么:对于for循环的每次迭代,您都会生成一个端口号并确保它是空闲的.然后,您生成一个例程,意图使用此端口(已经释放回可用端口池).你真的不知道例程什么时候开始.它可能在主例程(for循环)刚刚生成另一个自由端口时被激活 - 也许是同一个自由端口?或者也许另一个进程同时采用了这个端口.基本上你可以在一个端口上拥有竞争条件.
经过一些研究:
但是有一点需要注意.只要本地+远程对是唯一的,两个不同的套接字就可以绑定到同一个ip +端口.我曾经写过一篇关于它的回复.因此,当我一直在创造倾听者时,:0我能够得到"碰撞"; 证明netstat -an:
10.0.1.11.65245 *.* LISTEN
10.0.1.11.65245 17.143.164.101.5223 ESTABLISHED
Run Code Online (Sandbox Code Playgroud)
现在,问题是如果要显式绑定套接字正在使用的端口,这是不可能的.可能是因为你只能指定本地地址,并且在调用listen或connect之前就不会知道远程地址(我们现在讨论的是syscalls,而不是Go接口).换句话说,当您未指定端口时,OS有更广泛的选择.因此,如果它发生了一个本地地址,也被另一个套接字使用,你无法手动绑定它.
如何解决它:
正如我在评论中提到的,您的服务器进程应该使用:0表示法,以便能够从操作系统中选择可用资源.一旦它正在倾听,地址应该通知感兴趣的进程.例如,您可以通过文件或标准输出来执行此操作.