本文发布于Cylon的收藏册,转载请著名原文链接~
方法1:dial
使用 net.DialTimeout
去检查端口的技巧:
在通过Dial检查端口占用时,需要知道网络中常见的报错状态,而不是 err != nil
都为可用
Connection reset by peer
connection reset by peer 这种错误情况下有以下几种场景:
- 基于包过滤的防火墙给予
RST
;对于此情况,基于网络模型来说处于网络层与传输层之间的netfilter,如果是防火墙拒绝那么未到应用层无法确认端口 - 对端应用资源限制而reset,通常为负载过高;对于此场景是已到达应用层
- 客户端关闭了连接,而服务器还在给客户端发送数据;对于端口检查来说不会到这步
由上面可知,这种错误一定为占用
Connection timed out
Connection timed out 这种场景根本就dial不成功,go中给出了一个专门的事件 opErr.Timeout()
来说明这个错误,故此错误将不能确认端口是否占用
Connection refused
Connection refused 这种场景催在两种情况
- 对于 local 场景来说,这将表示端口未监听
- 对于远端场景来说,这种基本上表示 client 发往 remote ,remote不能接受
host:port
这个连接
通常对于存在两种情况,但多数为端口为监听
- Misconfiguration, such as where a user has mistyped the port number, or is using stale information about what port the service they require is running on.
- A service error, such as where the service that should be listening on a port has crashed or is otherwise unavailable.
所以此状态可以用于判断端口的状态,而对于端口检测通常为 local,所以可以用作判断依据
func checkPortIsAvailable(protocol string, port int) {
timeoutSecs := 3
addr, err := GetInterfaceIpv4Addr("eth0")
conn, err := net.DialTimeout(protocol, net.JoinHostPort(addr, strconv.Itoa(port)), time.Duration(timeoutSecs)*time.Second)
for {
if err != nil {
opErr, ok := err.(*net.OpError)
if ok && strings.Contains(opErr.Err.Error(), "refused") {
break
} else if opErr.Timeout() {
continue
} else {
continue
}
}
if conn != nil {
defer conn.Close()
continue
}
}
}
方法2:golib
库 github.com/antelman107/net-wait-go 可以用于等待端口直到状态为open,通过这种方法也可以很好的检测端口是否占用
本文发布于Cylon的收藏册,转载请著名原文链接~
链接:https://www.oomkill.com/2023/01/goskill-port-is-available/
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。