在达到超时之前,如何读取UDP连接?

cqc*_*law 2 concurrency udp network-programming go

我需要读取UDP流量,直到达到超时.我可以通过在UDPConn上调用SetDeadline并循环直到我得到I/O超时错误来做到这一点,但这似乎是hack-ish(基于错误条件的流量控制).以下代码段似乎更正确,但不会终止.在生产中,这显然会在goroutine中执行; 为了简单起见,它是作为主要功能编写的.

package main

import (
    "fmt"
    "time"
)

func main() {
    for {
        select {
        case <-time.After(time.Second * 1):
            fmt.Printf("Finished listening.\n")
            return
        default:
            fmt.Printf("Listening...\n")
            //read from UDPConn here
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么给定的程序不会终止?基于https://gobyexample.com/select,https://gobyexample.com/timeoutshttps://gobyexample.com/non-blocking-channel-operations,我希望上面的代码,选择默认的情况下,一秒钟,然后采取第一种情况,并打破循环.如何修改上面的代码段以实现循环和读取所需的效果,直到发生超时?

Sim*_*Fox 10

如果你不关心过去n秒的读取阻塞,那么循环到截止日期:

 deadline := time.Now().Add(n * time.Second)
 for time.Now().Before(deadline) {
    fmt.Printf("Listening...\n")
    //read from UDPConn here
 }
 fmt.Printf("Finished listening.\n")
Run Code Online (Sandbox Code Playgroud)

如果你确实希望在n几秒钟之后突破阻塞读取,那么设置一个截止日期并阅读,直到出现错误:

conn.SetReadDeadline(time.Now().Add(n * time.Second)
for {
   n, err := conn.Read(buf)
   if err != nil {
       if e, ok := err.(net.Error); !ok || !e.Timeout() {
           // handle error, it's not a timeout
       }
       break
   }
   // do something with packet here
}
Run Code Online (Sandbox Code Playgroud)

使用截止日期不是hacky.标准库在读取UDP连接时使用最后期限(请参阅dns客户端).

还有其他方法可以使用截止日期来打破阻塞读取:关闭连接或发送读取器识别的虚拟数据包.这些替代方案需要启动另一个goroutine,并且比设定截止日期要复杂得多.


One*_*One 4

time.After只需从循环外部分配通道即可for,否则每次循环时都会创建一个新的计时器。

例子:

func main() {
    ch := time.After(time.Second * 1)
L:
    for {
        select {
        case <-ch:
            fmt.Printf("Finished listening.\n")
            break L // have to use a label or it will just break select
        default:
            fmt.Printf("Listening...\n")
            //read from UDPConn here
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这在操场上不起作用。

  • @cqcallaw 在该示例中它会阻塞,直到计时器用完或通道返回某些内容,将“default”添加到“select”使其成为非阻塞。 (2认同)