How do I read a UDP connection until a timeout is reached?
I need to read UDP traffic until a timeout is reached. I can do this by calling SetDeadline on the UDPConn and looping until I get an I / O timeout error, but that seems like a hack-ish (error condition based flow control). The following code snippet seems more correct, but it doesn't end there. In production this will obviously be done in the larynx; it is written as the main function for simplicity.
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
}
}
}
Why doesn't this program end? Based on https://gobyexample.com/select , https://gobyexample.com/timeouts and https://gobyexample.com/non-blocking-channel-operations , I would expect the above code to select the case by default for one second, then take the first case and exit the loop. How can I modify the above snippet to achieve the desired loop and read effect until a timeout occurs?
source to share
Just assign the channel from time.After
outside the loop for
, otherwise you will just create a new timer every time you loop.
Example:
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
}
}
}
Please note that this does not work in the playground.
source to share
If you are not worried about the past n
seconds reading blocking , then loop to the deadline:
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")
If you want to exit the lock after n
seconds, then set a deadline and read before the error appears:
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 not a timeout
}
break
}
// do something with packet here
}
Using the deadline is not a hack. The standard library uses deadlines when reading UDP connections (see dns client ).
There are alternatives to using a deadline to abort a read lock: close the connection, or send a dummy packet that the reader recognizes. These alternatives require running a different goroutine and are much more difficult than setting a deadline.
source to share