- 改进了 TCPing 任务中对 host:port 格式的解析,支持 IPv6 地址格式并默认使用端口 80。 - 移除了不必要的空行以提升代码可读性。 - 更新了安装脚本,移除了不再使用的镜像源。
191 lines
4.1 KiB
Go
191 lines
4.1 KiB
Go
package handler
|
||
|
||
import (
|
||
"net"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
func handleTCPing(c *gin.Context, url string, params map[string]interface{}) {
|
||
// 获取seq参数
|
||
seq := ""
|
||
if seqVal, ok := params["seq"].(string); ok {
|
||
seq = seqVal
|
||
}
|
||
|
||
// 解析host:port格式,如果没有端口则默认80
|
||
var host string
|
||
var portStr string
|
||
var port int
|
||
|
||
// 检查是否是IPv6格式(如 [::1]:8080)
|
||
if strings.HasPrefix(url, "[") {
|
||
// IPv6格式
|
||
closeBracket := strings.LastIndex(url, "]")
|
||
if closeBracket == -1 {
|
||
c.JSON(200, gin.H{
|
||
"seq": seq,
|
||
"type": "ceTCPing",
|
||
"url": url,
|
||
"error": "格式错误,IPv6地址格式应为 [host]:port",
|
||
})
|
||
return
|
||
}
|
||
host = url[1:closeBracket]
|
||
if closeBracket+1 < len(url) && url[closeBracket+1] == ':' {
|
||
portStr = url[closeBracket+2:]
|
||
} else {
|
||
portStr = "80" // 默认端口
|
||
}
|
||
} else {
|
||
// 普通格式 host:port 或 host
|
||
lastColonIndex := strings.LastIndex(url, ":")
|
||
if lastColonIndex == -1 {
|
||
// 没有冒号,使用默认端口80
|
||
host = url
|
||
portStr = "80"
|
||
} else {
|
||
host = url[:lastColonIndex]
|
||
portStr = url[lastColonIndex+1:]
|
||
// 如果端口部分为空,使用默认端口80
|
||
if portStr == "" {
|
||
portStr = "80"
|
||
}
|
||
}
|
||
}
|
||
|
||
var err error
|
||
port, err = strconv.Atoi(portStr)
|
||
if err != nil {
|
||
c.JSON(200, gin.H{
|
||
"seq": seq,
|
||
"type": "ceTCPing",
|
||
"url": url,
|
||
"error": "端口格式错误",
|
||
})
|
||
return
|
||
}
|
||
|
||
// 解析hostname获取IP
|
||
var primaryIP string
|
||
ips, err := net.LookupIP(host)
|
||
if err == nil && len(ips) > 0 {
|
||
// 优先使用IPv4
|
||
for _, ip := range ips {
|
||
if ip.To4() != nil {
|
||
primaryIP = ip.String()
|
||
break
|
||
}
|
||
}
|
||
if primaryIP == "" && len(ips) > 0 {
|
||
primaryIP = ips[0].String()
|
||
}
|
||
}
|
||
|
||
// 执行多次TCP连接测试(默认10次,和PING一致)
|
||
const testCount = 10
|
||
var latencies []float64
|
||
successCount := 0
|
||
failureCount := 0
|
||
|
||
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()
|
||
|
||
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++
|
||
}
|
||
}
|
||
|
||
// 计算统计信息
|
||
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)
|
||
}
|