dongmi0760 2016-04-29 15:20
浏览 215
已采纳

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

So i have this code block for sending a message. The message which gets passed to c.outChan is transmitted and if an ack is recieved in return, a "true" will be passed through the c.buffer[nr].signaler channel. This seems to work fine, but if the message is dropped ( no ack recieved ), instead of reaching the timeout print, it just stoppes, and i don't know why. Here is the code:

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
", nr)
    case <-timeout:
        fmt.Println("-----------timeout-----------
")
        //resending
        c.send(nr)
    }
}

What am i doing wrong?

  • 写回答

1条回答 默认 最新

  • douzhanhui5662 2016-04-29 15:30
    关注

    You are using a switch for your channels, but you need a select. The switch doesn't know anything about channels and instead just tries to evaluate the expression in the case statements before the select. Your current code is equivalent to this:

    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
    ", nr)
        case tmp2 :
            fmt.Println("-----------timeout-----------
    ")
            //resending
            c.send(nr)
        }
    }
    

    Your code should look like this (using select instead of 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
    ", nr)
        case <-timeout:
            fmt.Println("-----------timeout-----------
    ")
            //resending
            c.send(nr)
        }
    }
    

    Also your timeout goroutine is unnecessary. Instead of calling time.After, waiting on the channel and then sending into your own timeout channel you could directly wait on time.After. Example:

    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
    ", nr)
        case <-time.After(c.retransTime):
            fmt.Println("-----------timeout-----------
    ")
            //resending
            c.send(nr)
        }
    }
    

    This is faster, more clear and uses less memory.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥170 如图所示配置eNSP
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥15 键盘指令混乱情况下的启动盘系统重装