From 2c990ea8a8aaf95ca1e208df373d668610477441 Mon Sep 17 00:00:00 2001 From: yoyo Date: Sun, 23 Nov 2025 04:28:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84tcping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/continuous/tcping.go | 29 +++++++- internal/handler/tcping.go | 129 +++++++++++++++++++++++++--------- 2 files changed, 125 insertions(+), 33 deletions(-) diff --git a/internal/continuous/tcping.go b/internal/continuous/tcping.go index 90a075d..8cfc585 100644 --- a/internal/continuous/tcping.go +++ b/internal/continuous/tcping.go @@ -140,22 +140,49 @@ func (t *TCPingTask) executeTCPing() map[string]interface{} { conn, err := net.DialTimeout("tcp", net.JoinHostPort(t.Host, strconv.Itoa(t.Port)), 5*time.Second) latency := time.Since(start).Milliseconds() + // 提取目标IP + var targetIP string + if conn != nil { + if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { + targetIP = addr.IP.String() + } + defer conn.Close() + } + + // 如果连接失败,从host解析 + if targetIP == "" { + ips, err := net.LookupIP(t.Host) + if err == nil && len(ips) > 0 { + // 优先使用IPv4 + for _, ip := range ips { + if ip.To4() != nil { + targetIP = ip.String() + break + } + } + if targetIP == "" && len(ips) > 0 { + targetIP = ips[0].String() + } + } + } + if err != nil { return map[string]interface{}{ "timestamp": time.Now().Unix(), "latency": -1, "success": false, "packet_loss": true, + "ip": targetIP, "error": err.Error(), } } - defer conn.Close() return map[string]interface{}{ "timestamp": time.Now().Unix(), "latency": float64(latency), "success": true, "packet_loss": false, + "ip": targetIP, } } diff --git a/internal/handler/tcping.go b/internal/handler/tcping.go index c64023c..a679cab 100644 --- a/internal/handler/tcping.go +++ b/internal/handler/tcping.go @@ -57,42 +57,107 @@ func handleTCPing(c *gin.Context, url string, params map[string]interface{}) { } } - // 执行TCP连接测试 - start := time.Now() - conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, portStr), 5*time.Second) - latency := time.Since(start).Milliseconds() + // 执行多次TCP连接测试(默认10次,和PING一致) + const testCount = 10 + var latencies []float64 + successCount := 0 + failureCount := 0 - if err != nil { - c.JSON(200, gin.H{ - "seq": seq, - "type": "ceTCPing", - "url": url, - "ip": primaryIP, - "host": host, - "port": port, - "latency": -1, - "error": err.Error(), - }) - return - } - defer conn.Close() + for i := 0; i < testCount; i++ { + start := time.Now() + conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, portStr), 5*time.Second) + latency := time.Since(start).Milliseconds() - // 如果之前没有获取到IP,从连接中获取 - if primaryIP == "" { - if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { - primaryIP = addr.IP.String() + if err == nil { + // 成功:记录延迟 + latencies = append(latencies, float64(latency)) + successCount++ + conn.Close() + + // 如果之前没有获取到IP,从连接中获取 + if primaryIP == "" { + if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { + primaryIP = addr.IP.String() + } + } + } else { + // 失败:记录为丢包 + failureCount++ } } - c.JSON(200, gin.H{ - "seq": seq, - "type": "ceTCPing", - "url": url, - "ip": primaryIP, - "host": host, - "port": port, - "latency": latency, - "success": true, - }) + // 计算统计信息 + packetsTotal := testCount + packetsRecv := successCount + packetsLosrat := float64(failureCount) / float64(testCount) * 100.0 + + var timeMin, timeMax, timeAvg float64 + if len(latencies) > 0 { + timeMin = latencies[0] + timeMax = latencies[0] + sum := 0.0 + for _, lat := range latencies { + if lat < timeMin { + timeMin = lat + } + if lat > timeMax { + timeMax = lat + } + sum += lat + } + timeAvg = sum / float64(len(latencies)) + } else { + // 全部失败 + timeMin = -1 + timeMax = -1 + timeAvg = -1 + } + + // 如果之前没有获取到IP,尝试从host解析 + if primaryIP == "" { + ips, err := net.LookupIP(host) + if err == nil && len(ips) > 0 { + for _, ip := range ips { + if ip.To4() != nil { + primaryIP = ip.String() + break + } + } + if primaryIP == "" && len(ips) > 0 { + primaryIP = ips[0].String() + } + } + } + + // 返回格式和PING一致 + result := gin.H{ + "seq": seq, + "type": "ceTCPing", + "url": url, + "ip": primaryIP, + "host": host, + "port": port, + "packets_total": strconv.Itoa(packetsTotal), + "packets_recv": strconv.Itoa(packetsRecv), + "packets_losrat": packetsLosrat, // float64类型,百分比值(如10.5表示10.5%) + } + + // 时间字段:如果是-1(全部失败),返回字符串"-",否则返回float64 + if timeMin < 0 { + result["time_min"] = "-" + result["time_max"] = "-" + result["time_avg"] = "-" + } else { + result["time_min"] = timeMin + result["time_max"] = timeMax + result["time_avg"] = timeAvg + } + + // 如果全部失败,添加error字段 + if successCount == 0 { + result["error"] = "所有TCP连接测试均失败" + } + + c.JSON(200, result) }