Golang net.http IPv4/IPv6 服务http ipv6
Golang 的网络服务,如果不指定IPv4 或 IPv6,如果VPS 同时支持 IPv4 和 IPv6,net.Listen() 只会监听 IPv6 地址。但这不影响客户端使用 IPv4 地址来访问。如下使用 netstat -lnt 来查看端口监听情况:
# netstat -lntActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::25 :::* LISTEN
tcp6 0 0 :::443 :::* LISTEN
tcp6 0 0 :::111 :::* LISTEN
tcp6 0 0
如何在启动网络服务时选择 IPv6?
在高层可以使用 http.ListenAndServe 来选择,如:
http.ListenAndServe("[2604:180:3:dd3::276e]:8083", nil) // 具体指定 tcp6
如果觉得具体指定 IPv6地址太麻烦,可以重构 ListenAndServe 函数,会用到 net.Listen 函数, 可以在该函数里指定 network ,可选 tcp、tcp4、tcp6。network 可选参数:
"tcp","tcp4" (IPv4-only),
"tcp6" (IPv6-only),
"udp",
"udp4" (IPv4-only),
"udp6" (IPv6-only),
"ip",
"ip4" (IPv4-only),
"ip6" (IPv6-only),
"unix",
"unixgram",
"unixpacket",
常用:
tcp 自动适配,优先IPv6tcp4 仅使用IPv4
tcp6 仅使用IPv6
重构的 ListenAndServe 函数示例:
package mainimport (
"fmt"
"net"
"net/http"
)
type helloHandler struct{}
func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))
}
func main() {
var err error
http.Handle("/", &helloHandler{})
//err = http.ListenAndServe(":8083", nil) // IPv4 或 IPv6
//err = http.ListenAndServe("[2604:180:3:dd3::276e]:8083", nil) // 具体指定,仅 IPv6
err = ListenAndServe(":8083", nil) // 重构的 ListenAndServe 函数
if err != nil {
fmt.Println(err)
}
}
//
type tcpKeepAliveListener struct {
*net.TCPListener
}
func ListenAndServe(addr string, handler http.Handler) error {
srv := &http.Server{Addr: addr, Handler: handler}
addr = srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp6", addr) // 仅指定 IPv6
if err != nil {
return err
}
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
客户端可以用下面的命令行检测 IPv6 服务:
curl "http://[2604:180:3:dd3::276e]:8083"curl -g -6 'http://[2604:180:3:dd3::276e]:8083/'
telnet -6 2604:180:3:dd3::276e 8083