Golang预绑定端口规避端口抢占问题
Golang 问题 端口 绑定 抢占 规避
2023-06-13 09:13:08 时间
文章目录
0. 背景介绍
接上篇文章 记time_wait状态引起的端口占用排查 介绍的排查 time_wait 的方法,并不能从根本上解决客户端随机分配的端口抢占本应分配给服务器的端口的问题
1. 方案描述
一般在服务器上都存在一些需要预留的端口,除了上篇介绍的 net.ipv4.ip_local_port_range
参数以外,没有很好的预留非连续端口的方式,只能提前绑定需要的端口
如果直接绑定或监听需要预分配的端口的话,当真正需要使用该端口时,还需要经历释放端口、重新绑定,并且还可能出现 Address is in use 的问题
解决方案是利用 SO_REUSEADDR和SO_REUSEPORT 参数的特性,在预绑定时设置这两个参数,后续再往该端口上绑定服务不会存在冲突,且客户端也无法进行抢占
2. 代码展示
- 根据网卡获取IP地址 要选取正确的IP地址,否则绑定无效
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
}
- 绑定端口
Golang 中包含
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
相关文章
- GoLang接口---上
- GoLang读写数据---上
- 在线客服系统源码开发实战总结:Golang实现CMS内容管理增删查改功能
- golang 切片
- golang面试题合集_slice
- Golang pprof 性能问题分析优化和实战经验
- RSS Can:使用 Golang 实现更好的 RSS Hub 服务(一)
- Golang语言情怀--第98期 区块链技术-以太坊公链合约部署-第4节:MetaMask钱包连接到本地环境
- golang源码分析:goreplay
- golang如何使用原生RPC及微服务简述
- Golang 库: golang slog 怎么设置日志 Debug 等级
- js格式化iso 8601格式的日期为其他格式-处理默认golang time类型格式问题
- 在Golang中常见的7种阻塞使用方式
- Debian下编译安装Golang