149 lines
3.0 KiB
Go
149 lines
3.0 KiB
Go
// Package nettest 提供网络连通性测试:TCP 端口探测与 ICMP Ping,持续统计成功率与延迟。
|
|
package nettest
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// TestResult 测试结果统计
|
|
type TestResult struct {
|
|
SuccessCount int // 成功计次
|
|
FailCount int // 失败计次
|
|
TotalCount int // 总数
|
|
TotalTime int // 总耗时
|
|
Avg int // 平均耗时 平均值
|
|
Min int // 最小耗时 最小值
|
|
Max int // 最大耗时 最大值
|
|
}
|
|
|
|
// NetTest 网络测试任务:后台协程周期性探测目标并累计统计
|
|
type NetTest struct {
|
|
Id int
|
|
Name string
|
|
Addr string
|
|
Port int
|
|
Timeout int64
|
|
TestResult
|
|
Ping *Ping
|
|
IsStop bool
|
|
IsEcho bool
|
|
IsUpdate bool
|
|
mux sync.Mutex
|
|
}
|
|
|
|
// NewNetTest 创建网络测试任务
|
|
// port 大于 0 时做 TCP 端口探测,等于 0 时做 ICMP Ping(需管理员权限)
|
|
// timeout 为超时毫秒数;echo 为 true 时控制台输出每次探测结果
|
|
func NewNetTest(id int, name string, addr string, port int, timeout int64, echo bool) *NetTest {
|
|
t := new(NetTest)
|
|
t.Id = id
|
|
t.Name = name
|
|
t.Addr = addr
|
|
t.Port = port
|
|
t.Timeout = timeout
|
|
t.IsEcho = echo
|
|
t.IsUpdate = false
|
|
t.Ping = NewPing(addr, port, timeout)
|
|
return t
|
|
}
|
|
|
|
// Set 运行中动态修改测试目标,下一轮探测生效
|
|
func (t *NetTest) Set(name string, addr string, port int, timeout int64) {
|
|
t.mux.Lock()
|
|
t.Name = name
|
|
t.Addr = addr
|
|
t.Port = port
|
|
t.Timeout = timeout
|
|
t.IsUpdate = true
|
|
t.mux.Unlock()
|
|
t.Ping = NewPing(addr, port, timeout)
|
|
}
|
|
|
|
// Start 启动后台测试协程
|
|
func (t *NetTest) Start() {
|
|
go t.process()
|
|
}
|
|
|
|
// Stop 停止测试协程
|
|
func (t *NetTest) Stop() {
|
|
t.mux.Lock()
|
|
t.IsStop = true
|
|
t.mux.Unlock()
|
|
}
|
|
|
|
// process 测试主循环:探测、累计统计、按剩余时间休眠
|
|
func (t *NetTest) process() {
|
|
isLoop := true
|
|
for isLoop {
|
|
|
|
t.mux.Lock()
|
|
timeout := int(t.Timeout)
|
|
if t.IsUpdate {
|
|
t.Ping.Set(t.Addr, t.Port, t.Timeout)
|
|
}
|
|
if t.IsStop {
|
|
isLoop = false
|
|
}
|
|
t.mux.Unlock()
|
|
if !isLoop {
|
|
break
|
|
}
|
|
et := t.Ping.Test()
|
|
if et > 0 {
|
|
timeout = timeout - et
|
|
}
|
|
if timeout > int(timeout) {
|
|
timeout = int(timeout)
|
|
}
|
|
t.mux.Lock()
|
|
t.TotalCount++
|
|
if et >= 0 {
|
|
t.SuccessCount++
|
|
} else {
|
|
t.FailCount++
|
|
}
|
|
if et == 0 {
|
|
t.TotalTime++
|
|
} else if et > 0 {
|
|
t.TotalTime += et
|
|
}
|
|
if t.SuccessCount > 0 {
|
|
t.Avg = t.TotalTime / t.SuccessCount
|
|
}
|
|
if (et < t.Min || t.Min == 0) && et > 0 {
|
|
t.Min = et
|
|
}
|
|
if et > t.Max {
|
|
t.Max = et
|
|
}
|
|
t.mux.Unlock()
|
|
|
|
if timeout > 0 {
|
|
time.Sleep(time.Duration(timeout) * time.Millisecond)
|
|
}
|
|
if t.IsEcho {
|
|
fmt.Printf("来自 %s 的回复: 时间=%dms\n", t.Addr, et)
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetResult 获取测试结果统计,isReset 为 true 时取完清零
|
|
func (t *NetTest) GetResult(isReset bool) TestResult {
|
|
t.mux.Lock()
|
|
r := TestResult{}
|
|
r = t.TestResult
|
|
if isReset {
|
|
t.SuccessCount = 0
|
|
t.FailCount = 0
|
|
t.TotalCount = 0
|
|
t.TotalTime = 0
|
|
t.Avg = 0
|
|
t.Min = 0
|
|
t.Max = 0
|
|
}
|
|
t.mux.Unlock()
|
|
return r
|
|
}
|