完成Bitsflow家人云的迁移工作
This commit is contained in:
730
1-代理Xray/99-网络质量分析/ne_quality_monitor_claude.go
Normal file
730
1-代理Xray/99-网络质量分析/ne_quality_monitor_claude.go
Normal file
@@ -0,0 +1,730 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
// ============ 通用数据结构 ============
|
||||
type TestPacket struct {
|
||||
SeqNum uint64
|
||||
Timestamp int64
|
||||
Type string // "tcp", "udp", "ping"
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type Stats struct {
|
||||
PacketsReceived uint64
|
||||
PacketsLost uint64
|
||||
LastSeqNum uint64
|
||||
RTTSamples []time.Duration
|
||||
}
|
||||
|
||||
type Metrics struct {
|
||||
PacketsSent uint64
|
||||
PacketsReceived uint64
|
||||
PacketsLost uint64
|
||||
RTTSamples []time.Duration
|
||||
MinRTT time.Duration
|
||||
MaxRTT time.Duration
|
||||
AvgRTT time.Duration
|
||||
Jitter time.Duration
|
||||
}
|
||||
|
||||
type TestReport struct {
|
||||
Timestamp time.Time
|
||||
TestDuration time.Duration
|
||||
TargetHost string
|
||||
TCPMetrics *Metrics
|
||||
UDPMetrics *Metrics
|
||||
TracerouteHops []HopInfo
|
||||
}
|
||||
|
||||
type HopInfo struct {
|
||||
TTL int
|
||||
Address string
|
||||
RTT time.Duration
|
||||
}
|
||||
|
||||
// ============ 服务端实现 ============
|
||||
type NetworkServer struct {
|
||||
tcpAddr string
|
||||
udpAddr string
|
||||
tcpStats *Stats
|
||||
udpStats *Stats
|
||||
statsLock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewNetworkServer(tcpPort, udpPort int) *NetworkServer {
|
||||
return &NetworkServer{
|
||||
tcpAddr: fmt.Sprintf(":%d", tcpPort),
|
||||
udpAddr: fmt.Sprintf(":%d", udpPort),
|
||||
tcpStats: &Stats{},
|
||||
udpStats: &Stats{},
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NetworkServer) Start() {
|
||||
log.Printf("========== 网络质量检测服务端 ==========")
|
||||
log.Printf("TCP监听端口: %s", ns.tcpAddr)
|
||||
log.Printf("UDP监听端口: %s", ns.udpAddr)
|
||||
log.Printf("服务器已启动,等待客户端连接...")
|
||||
log.Printf("========================================\n")
|
||||
|
||||
// 启动TCP服务器
|
||||
go ns.serveTCP()
|
||||
// 启动UDP服务器
|
||||
go ns.serveUDP()
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func (ns *NetworkServer) serveTCP() {
|
||||
listener, err := net.Listen("tcp", ns.tcpAddr)
|
||||
if err != nil {
|
||||
log.Fatalf("TCP监听失败: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Printf("TCP连接接受错误: %v", err)
|
||||
continue
|
||||
}
|
||||
go ns.handleTCPConnection(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NetworkServer) handleTCPConnection(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
log.Printf("[TCP] 新连接来自 %s", conn.RemoteAddr())
|
||||
|
||||
buf := make([]byte, 8192)
|
||||
for {
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Printf("[TCP] 连接 %s 断开", conn.RemoteAddr())
|
||||
return
|
||||
}
|
||||
|
||||
var packet TestPacket
|
||||
if err := json.Unmarshal(buf[:n], &packet); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
receiveTime := time.Now().UnixNano()
|
||||
ns.updateStats(ns.tcpStats, packet.SeqNum)
|
||||
|
||||
// 立即回显数据包
|
||||
response := TestPacket{
|
||||
SeqNum: packet.SeqNum,
|
||||
Timestamp: receiveTime,
|
||||
Type: "tcp_response",
|
||||
Data: packet.Data,
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(response)
|
||||
conn.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NetworkServer) serveUDP() {
|
||||
addr, err := net.ResolveUDPAddr("udp", ns.udpAddr)
|
||||
if err != nil {
|
||||
log.Fatalf("UDP地址解析失败: %v", err)
|
||||
}
|
||||
|
||||
conn, err := net.ListenUDP("udp", addr)
|
||||
if err != nil {
|
||||
log.Fatalf("UDP监听失败: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
log.Printf("[UDP] 监听在 %s", ns.udpAddr)
|
||||
|
||||
buf := make([]byte, 8192)
|
||||
for {
|
||||
n, remoteAddr, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Printf("UDP读取错误: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
var packet TestPacket
|
||||
if err := json.Unmarshal(buf[:n], &packet); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
receiveTime := time.Now().UnixNano()
|
||||
ns.updateStats(ns.udpStats, packet.SeqNum)
|
||||
|
||||
// 回显UDP数据包
|
||||
response := TestPacket{
|
||||
SeqNum: packet.SeqNum,
|
||||
Timestamp: receiveTime,
|
||||
Type: "udp_response",
|
||||
Data: packet.Data,
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(response)
|
||||
conn.WriteToUDP(data, remoteAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NetworkServer) updateStats(stats *Stats, seqNum uint64) {
|
||||
ns.statsLock.Lock()
|
||||
defer ns.statsLock.Unlock()
|
||||
|
||||
stats.PacketsReceived++
|
||||
|
||||
if seqNum > stats.LastSeqNum+1 {
|
||||
stats.PacketsLost += seqNum - stats.LastSeqNum - 1
|
||||
}
|
||||
stats.LastSeqNum = seqNum
|
||||
}
|
||||
|
||||
// ============ 客户端实现 ============
|
||||
type NetworkClient struct {
|
||||
targetHost string
|
||||
tcpPort int
|
||||
udpPort int
|
||||
testDuration time.Duration
|
||||
packetSize int
|
||||
reportFile string
|
||||
|
||||
tcpMetrics *Metrics
|
||||
udpMetrics *Metrics
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewNetworkClient(host string, tcpPort, udpPort int, duration time.Duration) *NetworkClient {
|
||||
return &NetworkClient{
|
||||
targetHost: host,
|
||||
tcpPort: tcpPort,
|
||||
udpPort: udpPort,
|
||||
testDuration: duration,
|
||||
packetSize: 1024,
|
||||
reportFile: "network_quality_report.json",
|
||||
tcpMetrics: &Metrics{MinRTT: time.Hour},
|
||||
udpMetrics: &Metrics{MinRTT: time.Hour},
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) testTCPLatency() error {
|
||||
addr := fmt.Sprintf("%s:%d", nc.targetHost, nc.tcpPort)
|
||||
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("TCP连接失败: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
log.Printf("[TCP] 开始延迟测试 -> %s", addr)
|
||||
|
||||
var seqNum uint64
|
||||
deadline := time.Now().Add(nc.testDuration)
|
||||
|
||||
for time.Now().Before(deadline) {
|
||||
seqNum++
|
||||
|
||||
packet := TestPacket{
|
||||
SeqNum: seqNum,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
Type: "tcp_probe",
|
||||
Data: make([]byte, nc.packetSize),
|
||||
}
|
||||
|
||||
sendTime := time.Now()
|
||||
|
||||
data, _ := json.Marshal(packet)
|
||||
if _, err := conn.Write(data); err != nil {
|
||||
nc.mu.Lock()
|
||||
nc.tcpMetrics.PacketsLost++
|
||||
nc.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
nc.mu.Lock()
|
||||
nc.tcpMetrics.PacketsSent++
|
||||
nc.mu.Unlock()
|
||||
|
||||
buf := make([]byte, 8192)
|
||||
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||
_, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
nc.mu.Lock()
|
||||
nc.tcpMetrics.PacketsLost++
|
||||
nc.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
rtt := time.Since(sendTime)
|
||||
nc.updateTCPMetrics(rtt)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
log.Printf("[TCP] 测试完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) testUDPLatency() error {
|
||||
addr := fmt.Sprintf("%s:%d", nc.targetHost, nc.udpPort)
|
||||
raddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UDP地址解析失败: %v", err)
|
||||
}
|
||||
|
||||
conn, err := net.DialUDP("udp", nil, raddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UDP连接失败: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
log.Printf("[UDP] 开始延迟测试 -> %s", addr)
|
||||
|
||||
var seqNum uint64
|
||||
deadline := time.Now().Add(nc.testDuration)
|
||||
sentPackets := make(map[uint64]time.Time)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 发送协程
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for time.Now().Before(deadline) {
|
||||
seqNum++
|
||||
|
||||
packet := TestPacket{
|
||||
SeqNum: seqNum,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
Type: "udp_probe",
|
||||
Data: make([]byte, nc.packetSize),
|
||||
}
|
||||
|
||||
sendTime := time.Now()
|
||||
nc.mu.Lock()
|
||||
sentPackets[seqNum] = sendTime
|
||||
nc.mu.Unlock()
|
||||
|
||||
data, _ := json.Marshal(packet)
|
||||
conn.Write(data)
|
||||
|
||||
nc.mu.Lock()
|
||||
nc.udpMetrics.PacketsSent++
|
||||
nc.mu.Unlock()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// 接收协程
|
||||
buf := make([]byte, 8192)
|
||||
for time.Now().Before(deadline.Add(3 * time.Second)) {
|
||||
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var response TestPacket
|
||||
if err := json.Unmarshal(buf[:n], &response); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
nc.mu.Lock()
|
||||
if sendTime, ok := sentPackets[response.SeqNum]; ok {
|
||||
rtt := time.Since(sendTime)
|
||||
nc.updateUDPMetrics(rtt)
|
||||
delete(sentPackets, response.SeqNum)
|
||||
}
|
||||
nc.mu.Unlock()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
nc.mu.Lock()
|
||||
nc.udpMetrics.PacketsLost = uint64(len(sentPackets))
|
||||
nc.mu.Unlock()
|
||||
|
||||
log.Printf("[UDP] 测试完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) performTraceroute() ([]HopInfo, error) {
|
||||
log.Printf("[Traceroute] 路由追踪到 %s", nc.targetHost)
|
||||
|
||||
hops := make([]HopInfo, 0, 30)
|
||||
maxTTL := 30
|
||||
timeout := 2 * time.Second
|
||||
|
||||
for ttl := 1; ttl <= maxTTL; ttl++ {
|
||||
hopInfo, reached, err := nc.probeHop(ttl, timeout)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
hops = append(hops, hopInfo)
|
||||
if hopInfo.Address != "*" {
|
||||
log.Printf(" %2d %-15s %.2fms", ttl, hopInfo.Address,
|
||||
float64(hopInfo.RTT.Microseconds())/1000.0)
|
||||
} else {
|
||||
log.Printf(" %2d *", ttl)
|
||||
}
|
||||
|
||||
if reached {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return hops, nil
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) probeHop(ttl int, timeout time.Duration) (HopInfo, bool, error) {
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
if err != nil {
|
||||
return HopInfo{}, false, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if err := conn.IPv4PacketConn().SetTTL(ttl); err != nil {
|
||||
return HopInfo{}, false, err
|
||||
}
|
||||
|
||||
msg := icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Seq: ttl,
|
||||
Data: []byte("TRACEROUTE"),
|
||||
},
|
||||
}
|
||||
|
||||
msgBytes, err := msg.Marshal(nil)
|
||||
if err != nil {
|
||||
return HopInfo{}, false, err
|
||||
}
|
||||
|
||||
dst, err := net.ResolveIPAddr("ip4", nc.targetHost)
|
||||
if err != nil {
|
||||
return HopInfo{}, false, err
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
if _, err := conn.WriteTo(msgBytes, dst); err != nil {
|
||||
return HopInfo{}, false, err
|
||||
}
|
||||
|
||||
reply := make([]byte, 1500)
|
||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
_, peer, err := conn.ReadFrom(reply)
|
||||
rtt := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
return HopInfo{TTL: ttl, Address: "*", RTT: 0}, false, nil
|
||||
}
|
||||
|
||||
hopAddr := peer.String()
|
||||
reachedTarget := (hopAddr == dst.String())
|
||||
|
||||
return HopInfo{
|
||||
TTL: ttl,
|
||||
Address: hopAddr,
|
||||
RTT: rtt,
|
||||
}, reachedTarget, nil
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) updateTCPMetrics(rtt time.Duration) {
|
||||
nc.mu.Lock()
|
||||
defer nc.mu.Unlock()
|
||||
|
||||
nc.tcpMetrics.PacketsReceived++
|
||||
nc.tcpMetrics.RTTSamples = append(nc.tcpMetrics.RTTSamples, rtt)
|
||||
|
||||
if rtt < nc.tcpMetrics.MinRTT {
|
||||
nc.tcpMetrics.MinRTT = rtt
|
||||
}
|
||||
if rtt > nc.tcpMetrics.MaxRTT {
|
||||
nc.tcpMetrics.MaxRTT = rtt
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) updateUDPMetrics(rtt time.Duration) {
|
||||
nc.udpMetrics.PacketsReceived++
|
||||
nc.udpMetrics.RTTSamples = append(nc.udpMetrics.RTTSamples, rtt)
|
||||
|
||||
if rtt < nc.udpMetrics.MinRTT {
|
||||
nc.udpMetrics.MinRTT = rtt
|
||||
}
|
||||
if rtt > nc.udpMetrics.MaxRTT {
|
||||
nc.udpMetrics.MaxRTT = rtt
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) calculateMetrics() {
|
||||
// 计算TCP平均RTT和抖动
|
||||
if len(nc.tcpMetrics.RTTSamples) > 0 {
|
||||
var sum time.Duration
|
||||
for _, rtt := range nc.tcpMetrics.RTTSamples {
|
||||
sum += rtt
|
||||
}
|
||||
nc.tcpMetrics.AvgRTT = sum / time.Duration(len(nc.tcpMetrics.RTTSamples))
|
||||
|
||||
var jitterSum time.Duration
|
||||
for i := 1; i < len(nc.tcpMetrics.RTTSamples); i++ {
|
||||
diff := nc.tcpMetrics.RTTSamples[i] - nc.tcpMetrics.RTTSamples[i-1]
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
jitterSum += diff
|
||||
}
|
||||
if len(nc.tcpMetrics.RTTSamples) > 1 {
|
||||
nc.tcpMetrics.Jitter = jitterSum / time.Duration(len(nc.tcpMetrics.RTTSamples)-1)
|
||||
}
|
||||
}
|
||||
|
||||
// 计算UDP平均RTT和抖动
|
||||
if len(nc.udpMetrics.RTTSamples) > 0 {
|
||||
var sum time.Duration
|
||||
for _, rtt := range nc.udpMetrics.RTTSamples {
|
||||
sum += rtt
|
||||
}
|
||||
nc.udpMetrics.AvgRTT = sum / time.Duration(len(nc.udpMetrics.RTTSamples))
|
||||
|
||||
var jitterSum time.Duration
|
||||
for i := 1; i < len(nc.udpMetrics.RTTSamples); i++ {
|
||||
diff := nc.udpMetrics.RTTSamples[i] - nc.udpMetrics.RTTSamples[i-1]
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
jitterSum += diff
|
||||
}
|
||||
if len(nc.udpMetrics.RTTSamples) > 1 {
|
||||
nc.udpMetrics.Jitter = jitterSum / time.Duration(len(nc.udpMetrics.RTTSamples)-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) generateReport(hops []HopInfo) error {
|
||||
nc.calculateMetrics()
|
||||
|
||||
report := TestReport{
|
||||
Timestamp: time.Now(),
|
||||
TestDuration: nc.testDuration,
|
||||
TargetHost: nc.targetHost,
|
||||
TCPMetrics: nc.tcpMetrics,
|
||||
UDPMetrics: nc.udpMetrics,
|
||||
TracerouteHops: hops,
|
||||
}
|
||||
|
||||
// 将报告序列化为JSON(单行,不格式化)
|
||||
data, err := json.Marshal(report)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 以追加模式打开文件,如果不存在则创建
|
||||
file, err := os.OpenFile(nc.reportFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("打开报告文件失败: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 写入JSON数据并添加换行符(JSON Lines格式)
|
||||
if _, err := file.Write(data); err != nil {
|
||||
return fmt.Errorf("写入报告数据失败: %v", err)
|
||||
}
|
||||
if _, err := file.WriteString("\n"); err != nil {
|
||||
return fmt.Errorf("写入换行符失败: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("测试报告已追加至: %s", nc.reportFile)
|
||||
|
||||
nc.printReport(&report)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) printReport(report *TestReport) {
|
||||
fmt.Println("\n" + strings.Repeat("=", 50))
|
||||
fmt.Println(" 网络质量检测报告")
|
||||
fmt.Println(strings.Repeat("=", 50))
|
||||
fmt.Printf("测试时间: %s\n", report.Timestamp.Format("2006-01-02 15:04:05"))
|
||||
fmt.Printf("目标主机: %s\n", report.TargetHost)
|
||||
fmt.Printf("测试时长: %v\n", report.TestDuration)
|
||||
fmt.Println(strings.Repeat("-", 50))
|
||||
|
||||
fmt.Println("\n【TCP 测试结果】")
|
||||
fmt.Printf(" 发送包数: %d\n", report.TCPMetrics.PacketsSent)
|
||||
fmt.Printf(" 接收包数: %d\n", report.TCPMetrics.PacketsReceived)
|
||||
if report.TCPMetrics.PacketsSent > 0 {
|
||||
lossRate := float64(report.TCPMetrics.PacketsLost) / float64(report.TCPMetrics.PacketsSent) * 100
|
||||
fmt.Printf(" 丢包数量: %d (丢包率: %.2f%%)\n", report.TCPMetrics.PacketsLost, lossRate)
|
||||
}
|
||||
if report.TCPMetrics.MinRTT < time.Hour {
|
||||
fmt.Printf(" 最小RTT: %v\n", report.TCPMetrics.MinRTT)
|
||||
fmt.Printf(" 平均RTT: %v\n", report.TCPMetrics.AvgRTT)
|
||||
fmt.Printf(" 最大RTT: %v\n", report.TCPMetrics.MaxRTT)
|
||||
fmt.Printf(" 抖动: %v\n", report.TCPMetrics.Jitter)
|
||||
}
|
||||
|
||||
fmt.Println("\n【UDP 测试结果】")
|
||||
fmt.Printf(" 发送包数: %d\n", report.UDPMetrics.PacketsSent)
|
||||
fmt.Printf(" 接收包数: %d\n", report.UDPMetrics.PacketsReceived)
|
||||
if report.UDPMetrics.PacketsSent > 0 {
|
||||
lossRate := float64(report.UDPMetrics.PacketsLost) / float64(report.UDPMetrics.PacketsSent) * 100
|
||||
fmt.Printf(" 丢包数量: %d (丢包率: %.2f%%)\n", report.UDPMetrics.PacketsLost, lossRate)
|
||||
}
|
||||
if report.UDPMetrics.MinRTT < time.Hour {
|
||||
fmt.Printf(" 最小RTT: %v\n", report.UDPMetrics.MinRTT)
|
||||
fmt.Printf(" 平均RTT: %v\n", report.UDPMetrics.AvgRTT)
|
||||
fmt.Printf(" 最大RTT: %v\n", report.UDPMetrics.MaxRTT)
|
||||
fmt.Printf(" 抖动: %v\n", report.UDPMetrics.Jitter)
|
||||
}
|
||||
|
||||
fmt.Println(strings.Repeat("=", 50))
|
||||
fmt.Printf("报告已保存至: %s\n\n", nc.reportFile)
|
||||
}
|
||||
|
||||
func (nc *NetworkClient) RunScheduledTests(interval time.Duration) {
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
log.Printf("\n========== 开始定时测试 [%s] ==========",
|
||||
time.Now().Format("2006-01-02 15:04:05"))
|
||||
|
||||
// 执行TCP测试
|
||||
if err := nc.testTCPLatency(); err != nil {
|
||||
log.Printf("TCP测试错误: %v", err)
|
||||
}
|
||||
|
||||
// 重置UDP指标
|
||||
nc.mu.Lock()
|
||||
nc.udpMetrics = &Metrics{MinRTT: time.Hour}
|
||||
nc.mu.Unlock()
|
||||
|
||||
// 执行UDP测试
|
||||
if err := nc.testUDPLatency(); err != nil {
|
||||
log.Printf("UDP测试错误: %v", err)
|
||||
}
|
||||
|
||||
// 执行Traceroute
|
||||
hops, err := nc.performTraceroute()
|
||||
if err != nil {
|
||||
log.Printf("Traceroute错误: %v", err)
|
||||
}
|
||||
|
||||
// 生成报告
|
||||
if err := nc.generateReport(hops); err != nil {
|
||||
log.Printf("报告生成错误: %v", err)
|
||||
}
|
||||
|
||||
// 重置TCP指标准备下一轮
|
||||
nc.mu.Lock()
|
||||
nc.tcpMetrics = &Metrics{MinRTT: time.Hour}
|
||||
nc.mu.Unlock()
|
||||
|
||||
log.Printf("========== 测试完成,等待下一轮 ==========\n")
|
||||
|
||||
<-ticker.C
|
||||
}
|
||||
}
|
||||
|
||||
// ============ 主程序 ============
|
||||
func main() {
|
||||
// 定义命令行参数
|
||||
var (
|
||||
mode = flag.String("mode", "", "运行模式: server(服务端) 或 client(客户端)")
|
||||
tcpPort = flag.Int("tcp", 9001, "TCP测试端口")
|
||||
udpPort = flag.Int("udp", 9002, "UDP测试端口")
|
||||
targetHost = flag.String("target", "", "目标主机地址(客户端模式必需)")
|
||||
testDuration = flag.Int("duration", 60, "单次测试时长(秒)")
|
||||
interval = flag.Int("interval", 3600, "定时测试间隔(秒), 0表示只执行一次")
|
||||
)
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "\n网络质量检测工具\n\n")
|
||||
fmt.Fprintf(os.Stderr, "用法:\n")
|
||||
fmt.Fprintf(os.Stderr, " 服务端模式: %s -mode server [-tcp 端口] [-udp 端口]\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, " 客户端模式: %s -mode client -target 目标IP [-tcp 端口] [-udp 端口] [-duration 秒] [-interval 秒]\n\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "参数说明:\n")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintf(os.Stderr, "\n示例:\n")
|
||||
fmt.Fprintf(os.Stderr, " # 启动服务端,使用默认端口\n")
|
||||
fmt.Fprintf(os.Stderr, " %s -mode server\n\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, " # 启动服务端,自定义端口\n")
|
||||
fmt.Fprintf(os.Stderr, " %s -mode server -tcp 8001 -udp 8002\n\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, " # 启动客户端,单次测试60秒\n")
|
||||
fmt.Fprintf(os.Stderr, " %s -mode client -target 192.168.1.100 -duration 60 -interval 0\n\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, " # 启动客户端,每小时测试一次\n")
|
||||
fmt.Fprintf(os.Stderr, " %s -mode client -target 192.168.1.100 -interval 3600\n\n", os.Args[0])
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
||||
// 验证参数
|
||||
if *mode == "" {
|
||||
fmt.Fprintf(os.Stderr, "错误: 必须指定运行模式 -mode server 或 -mode client\n\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
switch *mode {
|
||||
case "server":
|
||||
// 服务端模式
|
||||
server := NewNetworkServer(*tcpPort, *udpPort)
|
||||
server.Start()
|
||||
|
||||
case "client":
|
||||
// 客户端模式
|
||||
if *targetHost == "" {
|
||||
fmt.Fprintf(os.Stderr, "错误: 客户端模式必须指定 -target 参数\n\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
client := NewNetworkClient(*targetHost, *tcpPort, *udpPort, time.Duration(*testDuration)*time.Second)
|
||||
|
||||
if *interval == 0 {
|
||||
// 单次执行
|
||||
log.Printf("开始单次网络质量测试...")
|
||||
|
||||
if err := client.testTCPLatency(); err != nil {
|
||||
log.Printf("TCP测试错误: %v", err)
|
||||
}
|
||||
|
||||
if err := client.testUDPLatency(); err != nil {
|
||||
log.Printf("UDP测试错误: %v", err)
|
||||
}
|
||||
|
||||
hops, err := client.performTraceroute()
|
||||
if err != nil {
|
||||
log.Printf("Traceroute错误: %v", err)
|
||||
}
|
||||
|
||||
if err := client.generateReport(hops); err != nil {
|
||||
log.Printf("报告生成错误: %v", err)
|
||||
}
|
||||
} else {
|
||||
// 定时执行
|
||||
log.Printf("开始定时网络质量监控,间隔: %d秒", *interval)
|
||||
client.RunScheduledTests(time.Duration(*interval) * time.Second)
|
||||
}
|
||||
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "错误: 无效的运行模式 '%s',必须是 'server' 或 'client'\n\n", *mode)
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user