UDP Datagrams

In a connectionless protocol each message contains information about its origin and destination. There is no “session” established using a long-lived socket. UDP clients and servers make use of datagrams, which are individual messages containing source and destination information. There is no state maintained by these messages, unless the client or server does so. The messages are not guaranteed to arrive, or may arrive out of order.

The most common situation for a client is to send a message and hope that a reply arrives. The most common situation for a server would be to receive a message and then send one or more replies back to that client. In a peer-to-peer situation, though, the server may just forward messages to other peers.

The major difference between TCP and UDP handling for Go is how to deal with packets arriving from possibly multiple clients, without the cushion of a TCP session to manage things. The major calls needed are

  1. func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error)
  2. func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error)
  3. func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error)
  4. func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error
  5. func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error)

The client for a UDP time service doesn’t need to make many changes, just changing ...TCP... calls to ...UDP... calls:

  1. /* UDPDaytimeClient
  2. */
  3. package main
  4. import (
  5. "net"
  6. "os"
  7. "fmt"
  8. )
  9. func main() {
  10. if len(os.Args) != 2 {
  11. fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])
  12. os.Exit(1)
  13. }
  14. service := os.Args[1]
  15. udpAddr, err := net.ResolveUDPAddr("udp4", service)
  16. checkError(err)
  17. conn, err := net.DialUDP("udp", nil, udpAddr)
  18. checkError(err)
  19. _, err = conn.Write([]byte("anything"))
  20. checkError(err)
  21. var buf [512]byte
  22. n, err := conn.Read(buf[0:])
  23. checkError(err)
  24. fmt.Println(string(buf[0:n]))
  25. os.Exit(0)
  26. }
  27. func checkError(err error) {
  28. if err != nil {
  29. fmt.Fprintf(os.Stderr, "Fatal error %s", err.Error())
  30. os.Exit(1)
  31. }
  32. }

while the server has to make a few more:

  1. /* UDPDaytimeServer
  2. */
  3. package main
  4. import (
  5. "fmt"
  6. "net"
  7. "os"
  8. "time"
  9. )
  10. func main() {
  11. service := ":1200"
  12. udpAddr, err := net.ResolveUDPAddr("udp4", service)
  13. checkError(err)
  14. conn, err := net.ListenUDP("udp", udpAddr)
  15. checkError(err)
  16. for {
  17. handleClient(conn)
  18. }
  19. }
  20. func handleClient(conn *net.UDPConn) {
  21. var buf [512]byte
  22. _, addr, err := conn.ReadFromUDP(buf[0:])
  23. if err != nil {
  24. return
  25. }
  26. daytime := time.Now().String()
  27. conn.WriteToUDP([]byte(daytime), addr)
  28. }
  29. func checkError(err error) {
  30. if err != nil {
  31. fmt.Fprintf(os.Stderr, "Fatal error %s", err.Error())
  32. os.Exit(1)
  33. }
  34. }