Golang网络拨号相关问题探讨

Golang网络拨号相关问题探讨 我编写了一个测试连接时间的工具,但发现很多连接时间存在错误。 我看到很多连接时间大于最小时间限制,但抓包分析显示实际时间是正常的。 我不清楚问题出在哪里。 有人能帮我看看吗? 我的代码如下:

func main() {
var wg sync.WaitGroup
chV, chR := peashooter.Start(config.Config(), &wg)
wg.Wait()
func Start(config *config.GlobalConfig, wg *sync.WaitGroup) (chan time.Duration, chan time.Duration) {
vAddr := net.JoinHostPort(config.Vip, config.VipPort)
rAddr := net.JoinHostPort(config.Rip, config.RipPort)
chV := make(chan time.Duration, config.PacketCounter)
chR := make(chan time.Duration, config.PacketCounter)
chLimit := make(chan int, config.PackLimit)
timeout := time.Second * time.Duration(config.Timeout)
timemin := time.Second * time.Duration(config.TimeoutMin)
for i := 0; i < config.PacketCounter; i++ {
	wg.Add(1)
	go shooter(config.PacketType, vAddr, timeout, timemin, chLimit, chV, wg)
}

for i := 0; i < config.PacketCounter; i++ {
	wg.Add(1)
	go shooter(config.PacketType, rAddr, timeout, timemin, chLimit, chR, wg)
}
return chV, chR
func shooter(QType string, vAddr string, timeout time.Duration, timemin time.Duration, ChLimit chan int, ch chan time.Duration, wg *sync.WaitGroup) {
ChLimit <- 1
defer wg.Done()
start := time.Now()
conn, err := net.DialTimeout(QType, vAddr, timeout)
if err != nil {
	fmt.Println(err.Error())
	<-ChLimit
	return
}
defer conn.Close()
t := time.Now()
elapsed := t.Sub(start)
if elapsed.Seconds() > timemin.Seconds() {
	fmt.Println(conn.LocalAddr())
}
ch <- elapsed
<-ChLimit

更多关于Golang网络拨号相关问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang网络拨号相关问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题可能出现在时间比较的逻辑上。在Go语言中,直接比较time.DurationSeconds()方法返回的浮点数可能导致精度问题。timemin.Seconds()返回的是float64类型,而浮点数比较在边界情况下可能不准确。

更可靠的方式是直接比较time.Duration值:

func shooter(QType string, vAddr string, timeout time.Duration, timemin time.Duration, ChLimit chan int, ch chan time.Duration, wg *sync.WaitGroup) {
    ChLimit <- 1
    defer wg.Done()
    start := time.Now()
    conn, err := net.DialTimeout(QType, vAddr, timeout)
    if err != nil {
        fmt.Println(err.Error())
        <-ChLimit
        return
    }
    defer conn.Close()
    elapsed := time.Since(start)
    
    // 直接比较time.Duration,而不是比较Seconds()的返回值
    if elapsed > timemin {
        fmt.Printf("连接超时: %v, 本地地址: %v\n", elapsed, conn.LocalAddr())
    }
    ch <- elapsed
    <-ChLimit
}

另外,确保在main函数中正确读取channel中的数据,否则可能影响计时准确性:

func main() {
    var wg sync.WaitGroup
    chV, chR := peashooter.Start(config.Config(), &wg)
    wg.Wait()
    
    // 读取channel中的数据
    close(chV)
    close(chR)
    
    for v := range chV {
        fmt.Printf("VIP连接时间: %v\n", v)
    }
    for r := range chR {
        fmt.Printf("RIP连接时间: %v\n", r)
    }
}

Start函数中,建议在返回channel前启动goroutine来关闭channel:

func Start(config *config.GlobalConfig, wg *sync.WaitGroup) (chan time.Duration, chan time.Duration) {
    vAddr := net.JoinHostPort(config.Vip, config.VipPort)
    rAddr := net.JoinHostPort(config.Rip, config.RipPort)
    chV := make(chan time.Duration, config.PacketCounter)
    chR := make(chan time.Duration, config.PacketCounter)
    chLimit := make(chan int, config.PackLimit)
    timeout := time.Second * time.Duration(config.Timeout)
    timemin := time.Second * time.Duration(config.TimeoutMin)
    
    for i := 0; i < config.PacketCounter; i++ {
        wg.Add(1)
        go shooter(config.PacketType, vAddr, timeout, timemin, chLimit, chV, wg)
    }

    for i := 0; i < config.PacketCounter; i++ {
        wg.Add(1)
        go shooter(config.PacketType, rAddr, timeout, timemin, chLimit, chR, wg)
    }
    
    // 等待所有goroutine完成后关闭channel
    go func() {
        wg.Wait()
        close(chV)
        close(chR)
    }()
    
    return chV, chR
}

这样修改后,时间比较会更加准确,并且channel的处理也会更加规范。

回到顶部