- [0. 背景介绍](https://cloud.tencent.com/developer)
- [1. 方案描述](https://cloud.tencent.com/developer)
- [2. 代码展示](https://cloud.tencent.com/developer)
接上篇文章 记time_wait状态引起的端口占用排查 介绍的排查 time_wait 的方法,并不能从根本上解决客户端随机分配的端口抢占本应分配给服务器的端口的问题
一般在服务器上都存在一些需要预留的端口,除了上篇介绍的 net.ipv4.ip_local_port_range
参数以外,没有很好的预留非连续端口的方式,只能提前绑定需要的端口
如果直接绑定或监听需要预分配的端口的话,当真正需要使用该端口时,还需要经历释放端口、重新绑定,并且还可能出现 Address is in use 的问题
解决方案是利用 SO_REUSEADDR和SO_REUSEPORT 参数的特性,在预绑定时设置这两个参数,后续再往该端口上绑定服务不会存在冲突,且客户端也无法进行抢占
func GetLocalIPByEthName(eth ...string) (string, error) {
interfaces, err := net.Interfaces()
if err != nil {
return "", err
}
for _, i := range interfaces {
for _, ethName := range eth {
if ethName == i.Name {
byname, err := net.InterfaceByName(i.Name)
if err != nil {
return "", err
}
addresses, err := byname.Addrs()
for _, v := range addresses {
if n, ok := v.(*net.IPNet); ok {
return n.IP.String(), nil
}
}
}
}
}
return "", nil
}
syscall
包,可以调用系统函数。需要注意的是这里只用绑定,不需要 Listen,如果进入 Listen 状态后就无法再进行绑定了func BindPorts(serverList []string) error {
for _, server := range serverList {
if len(server) <= 0 {
continue
}
port := SplitPort(server)
if fd, err := syscall.Socket(syscall.AF_INET, syscall.O_NONBLOCK|syscall.SOCK_STREAM, 0); err == nil && port > 0 {
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1) // 设置复用端口
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
addr := syscall.SockaddrInet4{Port: port}
copy(addr.Addr[:], net.ParseIP("0.0.0.0").To4())
syscall.Bind(fd, &addr)
}
}
return nil
}
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3fbaklghqlgk0