我的(OS X 10.13.5)系统上端口8888已经被运行在docker容器中的进程绑定:
$ netstat -an | grep 8888
tcp6 0 0 ::1.8888 *.* LISTEN
tcp4 0 0 *.8888 *.* LISTEN
这是一个关于IT技术的翻译内容:一个Python程序试图绑定到该端口(使用尽可能接近golang套接字选项的方式),但以我预期的方式失败了:
import socket
import fcntl
import os
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
flag = fcntl.fcntl(sock.fileno(), fcntl.F_GETFL)
fcntl.fcntl(sock.fileno(), fcntl.F_SETFL, flag | os.O_NONBLOCK)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(("0.0.0.0", 8888))
sock.listen(5)
main()
出现以下错误:
$ python test.py
Traceback (most recent call last):
File "test.py", line 15, in <module>
main()
File "test.py", line 11, in main
sock.bind(("0.0.0.0", 8888))
OSError: [Errno 48] Address already in use
但是,通过 net.Listen
创建连接的 Go 程序并不会像我预期的那样失败:
package main
import (
"fmt"
"net"
)
func main() {
_, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Printf("Connection error: %s\n", err)
} else {
fmt.Println("Listening")
}
}
成功的要素包括:
$ go run test.go
Listening
一位同事报告说,在相同的设置下,他的Ubuntu系统正确地使go程序失败。
为什么Mac上会成功,我如何让net.Listen在绑定到端口8888时显示错误?
编辑:如果我使用一个简单的go程序占用端口8888:
package main
import (
"log"
"net/http"
)
func main() {
log.Fatal(http.ListenAndServe("0.0.0.0:8888", nil))
}
然后test.go
无法绑定端口。但是运行基本上就是那个 ^^^ 的docker进程并没有导致它失败。
编辑2:如果我指定“tcp4”,那么程序确实会像我期望的那样失败。如果我指定“tcp6”,它会成功,但netstat会说它绑定到*
而不是::1
:
$ netstat -an | grep 8888
tcp6 0 0 *.8888 *.* LISTEN
tcp6 0 0 ::1.8888 *.* LISTEN
tcp4 0 0 *.8888 *.* LISTEN
因此,指定"tcp4"将解决我的实际问题,但我真的想了解"tcp46"连接类型到底是怎么回事,但我找不到任何文档资料。求助!
http.ListenAndServe
也会在内部调用net.Listen("tcp", addr)
:https://github.com/golang/go/blob/master/src/net/http/server.go#L2728 - Emile Pelstime.Sleep(10 * time.Second)
调用并在其运行时获取netstat
输出可能会很有用。 - chuckxlsof -i -T f | grep 8888
的输出吗? - chuckxlsof -i -T f | grep 8888
在程序运行前和运行期间都是空的,你确定这些是正确的Mac lsof选项吗? - llimllib