From 3739768c45f867238a12e22d662d6bf6a9d9cff3 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Wed, 13 May 2026 00:11:33 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E7=AB=AF=E5=8F=A3=E6=89=AB=E6=8F=8F?= =?UTF-8?q?=E8=87=AA=E9=80=82=E5=BA=94=E8=B6=85=E6=97=B6=EF=BC=8C=E5=9F=BA?= =?UTF-8?q?=E4=BA=8E=20RTT=20=E9=87=87=E6=A0=B7=E5=8A=A8=E6=80=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E8=BF=9E=E6=8E=A5=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/adaptive_timeout.go | 92 ++++++++++++++++++++++++++++++++++++++++ core/port_scan.go | 8 +++- 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 core/adaptive_timeout.go diff --git a/core/adaptive_timeout.go b/core/adaptive_timeout.go new file mode 100644 index 0000000..fb05660 --- /dev/null +++ b/core/adaptive_timeout.go @@ -0,0 +1,92 @@ +package core + +import ( + "math" + "sync" + "time" +) + +// AdaptiveTimeout 基于 RTT 采样的自适应超时计算器 +// 算法:timeout = mean(RTT) + 4 * stddev(RTT),clamp 到 [min, max] +// 冷启动阶段(样本不足)返回用户配置的固定超时 +type AdaptiveTimeout struct { + mu sync.Mutex + samples []float64 // 环形缓冲区,单位 ms + pos int // 写入位置 + count int // 已采集总数 + size int // 缓冲区容量 + minTO time.Duration + maxTO time.Duration + warmup int // 冷启动所需最小样本数 + cachedTO time.Duration + dirty bool +} + +// NewAdaptiveTimeout 创建自适应超时计算器 +// maxTimeout: 用户配置的超时上限(即原始固定超时) +func NewAdaptiveTimeout(maxTimeout time.Duration) *AdaptiveTimeout { + return &AdaptiveTimeout{ + samples: make([]float64, 64), + size: 64, + minTO: 100 * time.Millisecond, + maxTO: maxTimeout, + warmup: 10, + } +} + +// Record 记录一次成功连接的 RTT +func (a *AdaptiveTimeout) Record(rtt time.Duration) { + a.mu.Lock() + a.samples[a.pos%a.size] = float64(rtt.Milliseconds()) + a.pos++ + a.count++ + a.dirty = true + a.mu.Unlock() +} + +// Timeout 获取当前推荐超时值 +// 样本不足时返回 maxTO(冷启动) +func (a *AdaptiveTimeout) Timeout() time.Duration { + a.mu.Lock() + defer a.mu.Unlock() + + if a.count < a.warmup { + return a.maxTO + } + + if !a.dirty { + return a.cachedTO + } + + n := a.size + if a.count < a.size { + n = a.count + } + + var sum float64 + for i := 0; i < n; i++ { + sum += a.samples[i] + } + mean := sum / float64(n) + + var variance float64 + for i := 0; i < n; i++ { + d := a.samples[i] - mean + variance += d * d + } + stddev := math.Sqrt(variance / float64(n)) + + ms := mean + 4*stddev + to := time.Duration(ms) * time.Millisecond + + if to < a.minTO { + to = a.minTO + } + if to > a.maxTO { + to = a.maxTO + } + + a.cachedTO = to + a.dirty = false + return to +} diff --git a/core/port_scan.go b/core/port_scan.go index a74d42a..6632196 100644 --- a/core/port_scan.go +++ b/core/port_scan.go @@ -173,6 +173,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout // 初始化并发控制 to := time.Duration(timeout) * time.Second + adaptiveTO := NewAdaptiveTimeout(to) var count int64 collector := newResultCollector() failedCollector := &failedPortCollector{} @@ -191,7 +192,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout }() addr := fmt.Sprintf("%s:%d", taskInfo.host, taskInfo.port) - scanSinglePort(ctx, taskInfo.host, taskInfo.port, addr, to, &count, collector, failedCollector, session) + scanSinglePort(ctx, taskInfo.host, taskInfo.port, addr, adaptiveTO, &count, collector, failedCollector, session) common.UpdateProgressBar(1) }, state) if err != nil { @@ -356,14 +357,17 @@ func buildServiceLogMessage(addr string, serviceInfo *ServiceInfo, isWeb bool) s } // scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本) -func scanSinglePort(ctx context.Context, host string, port int, addr string, timeout time.Duration, count *int64, collector *resultCollector, failedCollector *failedPortCollector, session *common.ScanSession) { +func scanSinglePort(ctx context.Context, host string, port int, addr string, adaptiveTO *AdaptiveTimeout, count *int64, collector *resultCollector, failedCollector *failedPortCollector, session *common.ScanSession) { config := session.Config + timeout := adaptiveTO.Timeout() // 步骤1:建立连接 + start := time.Now() conn, err := connectWithRetry(ctx, session, addr, timeout, 2) if err != nil { handleConnectionFailure(err, host, port, addr, failedCollector) return } + adaptiveTO.Record(time.Since(start)) // 步骤1.5:代理连接深度验证(防止透明代理/全回显代理的假连接问题) valid, verifyMethod := verifyProxyConnectionDeep(conn, addr)