应使用 net.dialtimeout 而非 net.dial 进行端口探测,因其可显式控制超时(建议 300–500ms),避免 goroutine 泄露、cpu 占满和扫描失控;须用带缓冲 channel 限并发(100–500)、区分 timeout 与 connection refused 错误,并及时关闭 conn 防 fd 泄露。

用 net.DialTimeout 判断单个端口是否开放,别用 net.Dial
直接调用 net.Dial 在目标端口无响应时会卡住默认超时(通常 30 秒以上),根本没法做并发扫描。必须用 net.DialTimeout 显式控制连接等待时间,否则 goroutine 会大量堆积、内存暴涨、扫描完全失控。
常见错误现象:goroutine leak、程序卡死、CPU 占满但没结果;本质是 TCP SYN 发出后没收到 RST/ACK,net.Dial 死等。
- 超时设成
500 * time.Millisecond比较稳妥:局域网可压到100ms,公网建议不短于300ms - 协议固定用
"tcp",别传"tcp4"或"tcp6"—— 后者在双栈环境可能触发额外 DNS 查询或 fallback,拖慢速度 - 地址格式必须是
"host:port"字符串,比如"192.168.1.1:22";不要自己拼 IP 和端口再解析,避免重复调用net.ResolveTCPAddr
用带缓冲的 channel 控制并发数,别用 runtime.GOMAXPROCS 或无限制启 goroutine
扫 65535 个端口,如果每端口起一个 goroutine,瞬间上万协程,调度开销远超 IO,反而更慢,还容易被目标主机限速或拉黑。真正有效的并发靠的是 channel 限流,不是“多开”。
使用场景:内网资产探测、CI 环境服务健康检查、渗透测试预检 —— 都需要稳定可控的并发节奏。
- 缓冲 channel 容量建议设为
100 ~ 500:小网段(如/24)用 100,大范围扫描用 300~500 - 不要依赖
runtime.GOMAXPROCS调节——它管的是 OS 线程数,和 goroutine 并发量无关 - 每个 goroutine 扫完一个端口就发结果到结果 channel,主 goroutine 用
range接收,避免用sync.WaitGroup+ 全局 slice 收集(竞态风险高)
处理 i/o timeout 和 connection refused 要区分对待
这两个错误看起来都是“连不上”,但语义完全不同:connection refused 是对方明确回了 RST,说明端口存在且关闭;i/o timeout 是 SYN 发出去没回音,可能是防火墙丢包、主机宕机、中间设备拦截,也可能是端口真开着但服务不响应。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
性能影响:把 timeout 当作“关闭”处理会漏掉真实开放的端口(比如某些 IDS 后面的服务);全当“开放”又会误报太多。
- 只把
connection refused和no route to host视为“确定关闭” -
i/o timeout标记为unknown,后续可单独重试(加长 timeout 或换源 IP) - 别用
strings.Contains(err.Error(), "timeout")判断——应检查err是否实现了net.Error接口并调用.Timeout()方法
扫完记得关掉 net.Conn,哪怕只做了 Dial
很多人以为 net.DialTimeout 失败就不用管资源了,其实只要返回了非 nil 的 net.Conn,就必须 Close()。否则 fd 泄露,扫几百个端口后就报 too many open files。
容易踩的坑:在 if err != nil 分支里直接 return,忘了 close 成功建立的连接;或者用 defer conn.Close() 但 defer 在函数退出才执行,而 goroutine 已经跑飞了。
- 正确写法:用
if conn != nil { defer conn.Close() }包裹整个逻辑块 - 更安全的做法:统一用
defer func() { if conn != nil { conn.Close() } }() - Windows 下尤其敏感,Linux 默认 ulimit -n 是 1024,扫满就崩
端口扫描真正的难点不在并发模型,而在如何平衡速度、准确性和隐蔽性——超时设太短漏报,太长拖垮效率;并发设太高触发防护,太低浪费时间;错误分类错一次,整批结果就不可信。这些细节没对齐,代码写得再“Go style”也没用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










