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

标签 concurrency go network-programming udp

我需要读取 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
        }
    }
}

为什么给定的程序没有终止?基于https://gobyexample.com/select , https://gobyexample.com/timeouts , 和 https://gobyexample.com/non-blocking-channel-operations ,我希望上面的代码选择默认情况一秒钟,然后选择第一种情况并跳出循环。我如何修改上面的代码片段以实现循环和读取直到发生超时的预期效果?

最佳答案

如果您不担心超过 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")

如果你确实想在 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
}

使用截止日期并不是 hacky。标准库在读取 UDP 连接时使用截止时间(参见 dns client )。

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

关于concurrency - 在达到超时之前如何读取 UDP 连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26081073/

相关文章:

对外暴露的 Docker 端口

C# 游戏网络库

java - "fast-path"无竞争同步是什么意思?

Golang 子项目或子模块依赖项

go - 如果任何 channel 关闭,有没有办法中断选择?

android - Android 应用通过 post 发送的参数在 Go 语言编写的后端服务器上始终为空

python多进程固定

c - 如何防止此 pthread 同步内存踩踏?

PHP Apache 增加每个客户端的最大并发连接数

java - MulticastSocket.joinGroup() 错误