Golang为什么这个超时方案不起作用?

时间:2016-04-29 15:20:31

标签: go network-programming udp timeout

所以我有这个代码块用于发送消息。传递给c.outChan的消息被传输,如果收到ack,则“true”将通过c.buffer [nr] .signaler通道传递。这似乎工作正常,但如果消息被删除(没有收到ack),而不是达到超时打印,它只是停止,我不知道为什么。这是代码:

func (c *uConnection) send(nr uint32) {
    //transmitt message
    c.outChan <- c.buffer[nr].msg
    timeout := make(chan bool, 1)
    go func() {
        timeoutTimer := time.After(c.retransTime)
        <-timeoutTimer
        timeout <- true
    }()
    switch {
    case <-c.buffer[nr].signaler:
        fmt.Printf("Ack confirmed: %v\n", nr)
    case <-timeout:
        fmt.Println("-----------timeout-----------\n")
        //resending
        c.send(nr)
    }
}

我做错了什么?

1 个答案:

答案 0 :(得分:4)

您正在为频道使用开关,但需要选择。交换机对通道一无所知,只是尝试在select语句之前评估case语句中的表达式。您当前的代码与此相同:

func (c *uConnection) send(nr uint32) {
    //transmitt message
    c.outChan <- c.buffer[nr].msg
    timeout := make(chan bool, 1)
    go func() {
        timeoutTimer := time.After(c.retransTime)
        <-timeoutTimer
        timeout <- true
    }()
    tmp1 := <-c.buffer[nr].signaler // this will block
    tmp2 := <-timeout
    switch {
    case tmp1 :
        fmt.Printf("Ack confirmed: %v\n", nr)
    case tmp2 :
        fmt.Println("-----------timeout-----------\n")
        //resending
        c.send(nr)
    }
}

您的代码应该如下所示(使用select而不是switch):

func (c *uConnection) send(nr uint32) {
    //transmitt message
    c.outChan <- c.buffer[nr].msg
    timeout := make(chan bool, 1)
    go func() {
        timeoutTimer := time.After(c.retransTime)
        <-timeoutTimer
        timeout <- true
    }()
    select {
    case <-c.buffer[nr].signaler:
        fmt.Printf("Ack confirmed: %v\n", nr)
    case <-timeout:
        fmt.Println("-----------timeout-----------\n")
        //resending
        c.send(nr)
    }
}

此外,您的超时goroutine也是不必要的。而不是调用time.After,等待频道,然后发送到你自己的超时频道,你可以直接等待准时。后。例如:

func (c *uConnection) send(nr uint32) {
    //transmitt message
    c.outChan <- c.buffer[nr].msg
    select {
    case <-c.buffer[nr].signaler:
        fmt.Printf("Ack confirmed: %v\n", nr)
    case <-time.After(c.retransTime):
        fmt.Println("-----------timeout-----------\n")
        //resending
        c.send(nr)
    }
}

这更快,更清晰,使用更少的内存。