应使用 net.dialtimeout 进行 tcp 端口探测,而非 net.listen;需设置合理超时(内网200ms、公网≥1s)、控制并发数(局域网≤500、云服务器≤50),并区分 connection refused(端口关闭)与 i/o timeout(状态未知)。

用 net.DialTimeout 做最简 TCP 端口探测,别碰 net.Listen
端口扫描器不是监听服务,而是主动发起连接试探。Golang 里最直接的方式就是用 net.DialTimeout,它能在超时前返回连接是否成功;用 net.Listen 或自己写 socket bind/listen 是完全走错方向——那是在模拟被扫者,不是扫描者。
常见错误是把扫描逻辑写成阻塞式同步循环,扫 65535 个端口等十几分钟,实际只需并发控制 + 超时约束:
-
timeout建议设为 500ms~2s,内网可压到 200ms,公网别低于 1s,否则大量i/o timeout掩盖真实关闭状态 - 并发数别硬写
runtime.NumCPU(),局域网可开 500 协程,云服务器扫外网建议 ≤50,否则发包过猛触发目标防火墙限速或本机socket: too many open files - 别用
net.Dial(无超时),它默认阻塞约 2 分钟,会卡死整个 goroutine
如何正确处理 connection refused 和 i/o timeout
这两个错误含义截然不同,但新手常当成“端口关了”一概忽略:
-
connection refused:TCP SYN-ACK 收到了,但目标端口没服务在 listen → 端口明确关闭(closed) -
i/o timeout:SYN 发出去后没回包 → 可能被防火墙 DROP、主机不存在、路由中断,也可能是端口开放但过滤了 ICMP/不回 RST → 属于“未知状态(filtered)”,不能简单跳过 - 真正开放的端口,
net.DialTimeout返回nil error,此时记得conn.Close(),否则 fd 泄漏
用 sync.WaitGroup + chan 控制并发,别用 time.Sleep 等协程结束
手动 sleep 几秒再判断扫描完成,是典型竞态隐患。goroutine 启太快、结束太慢,sleep 时间估不准就会丢结果或 panic。
正确做法是:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 启动前
wg.Add(n),每个 goroutine 结束调wg.Done() - 结果统一写进带缓冲的
chan PortResult(如make(chan PortResult, 1000)),避免 goroutine 因 channel 满而阻塞 - 另起一个 goroutine 收集结果,主 goroutine 用
wg.Wait()等全部探测结束,再close(ch)
示例关键片段:
for port := range ports {
wg.Add(1)
go func(p int) {
defer wg.Done()
conn, err := net.DialTimeout("tcp", net.JoinHostPort(target, strconv.Itoa(p)), 1*time.Second)
if err == nil {
resultCh <h3>为什么不用 <code>syscall.Socket</code> 写原始 SYN 扫描</h3><p>想绕过三次握手做半开扫描(SYN scan)?Golang 标准库不暴露 raw socket 接口,<code>syscall.Socket</code> 在非 root 用户下无法创建 <code>AF_INET, SOCK_RAW</code>,Linux 下还受 <code>cap_net_raw</code> 限制,Windows 更是基本不可行。</p><p>真有高性能/隐蔽性需求,现实路径只有两条:</p>
- 调用系统命令(如
exec.Command("nmap", "-sS", ...)),但失去 Go 的跨平台控制力 - 用
cgo封装 libpcap 或直接 syscall,代价是编译复杂、权限提升、维护成本陡增
对绝大多数用途,TCP connect 扫描已足够 —— 它不依赖 root,兼容所有平台,且现代防火墙对 connect 扫描的识别和拦截并不比 SYN 扫描更低。
真正容易被忽略的是:目标主机的 TCP backlog 队列长度、本机 ephemeral port 范围、以及云厂商安全组默认只放行少数端口 —— 这些都会让扫描结果出现偏差,比代码逻辑更值得先确认。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










