howto-udp-broadcast-golang
howto-udp-broadcast-golang copied to clipboard
Sample code and instructions on how to send and receive UDP broadcast packets in the Go programming language.
Howto: UDP broadcast in Go
Sample code and instructions on how to send and receive UDP broadcast packets in the Go programming language.
Introduction
A common method to trasmit informations to multiple devices connected to the same network consists in using the UDP transport layer and sending the packets to the network broadcast address. The router will take care of propagating the packets to each connected device. There are at least two advantages with respect to normal network communication:
- transmission is much more efficient, as a single stream of data is used for communicating with multiple devices
- it is not necessary to know in advance the addresses of the recipients
The Go programming languages offers at least 4 ways to send UDP broadcast packets, the situation is not very clear and that's the reason why this guide is being written.
Sending
Let's assume we want to transmit the ascii-encoded phrase "data to transmit" though port 8829
in a network with IP 192.168.7.2
and broadcast address 192.168.7.255
.
The first (and preferred) method consists in using the net.ListenPacket() function:
package main
import (
"net"
"fmt"
)
func main() {
pc, err := net.ListenPacket("udp4", ":8829")
if err != nil {
panic(err)
}
defer pc.Close()
addr,err := net.ResolveUDPAddr("udp4", "192.168.7.255:8829")
if err != nil {
panic(err)
}
_,err := pc.WriteTo([]byte("data to transmit"), addr)
if err != nil {
panic(err)
}
}
A second method consists in using the net.ListenUDP() function:
package main
import (
"net"
)
func main() {
listenAddr,err := net.ResolveUDPAddr("udp4", ":8829")
if err != nil {
panic(err)
}
list, err := net.ListenUDP("udp4", listenAddr)
if err != nil {
panic(err)
}
defer list.Close()
addr,err := net.ResolveUDPAddr("udp4", "192.168.7.255:8829")
if err != nil {
panic(err)
}
_,err := list.WriteTo([]byte("data to transmit"), addr)
if err != nil {
panic(err)
}
}
A third method consists in using the net.DialUDP() function:
package main
import (
"net"
)
func main() {
local,err := net.ResolveUDPAddr("udp4", ":8829")
if err != nil {
panic(err)
}
remote,err := net.ResolveUDPAddr("udp4", "192.168.7.255:8829")
if err != nil {
panic(err)
}
list, err := net.DialUDP("udp4", local, remote)
if err != nil {
panic(err)
}
defer list.Close()
_,err := list.Write([]byte("data to transmit"))
if err != nil {
panic(err)
}
}
A fourth and shorter way consists in using the net.Dial() function if the local address / port don't matter:
package main
import "net"
func main() {
conn, err := net.Dial("udp", "192.168.7.255:8829")
if err != nil {
panic(err)
}
defer conn.Close()
_, err := conn.Write([]byte("data to transmit"))
if err != nil {
panic(err)
}
All four methods work and their result is indistinguishable. By looking at the Go source code, it is possible to assert that:
-
net.ListenPacket() and net.ListenUDP() use a nearly identical identical procedure, as they both call the same system functions, the only difference is that net.ListenPacket() converts the desired listen address (
:8829
) into an UDPAddr structure, while net.ListenUDP() requires directly an UDPAddr structure; - net.DialUDP() uses a different route and also provides a Write() function to write directly to the broadcast address. This could be confusing, as Go always work with WriteTo() and ReadFrom() when dealing with UDP connections.
Conclusion: I use with the ListenPacket() solution as it is the simpler one.
Receiving
Data can be received with a standard UDP server listening on the provided port:
package main
import (
"fmt"
"net"
)
func main() {
pc,err := net.ListenPacket("udp4", ":8829")
if err != nil {
panic(err)
}
defer pc.Close()
buf := make([]byte, 1024)
n,addr,err := pc.ReadFrom(buf)
if err != nil {
panic(err)
}
fmt.Printf("%s sent this: %s\n", addr, buf[:n])
}