您的位置:

Golang UDP详解

一、UDP协议简介

UDP(User Datagram Protocol,用户数据报协议)是Internet传输层协议之一,与TCP(Transmission Control Protocol,传输控制协议)一样工作于 OSI模型的传输层。

和TCP不同的是,UDP不必在发数据前先建立连接,因此传输数据的速度更快,但是可靠性较差。而且处理的数据包大小也有限制,MTU通常为1500字节。

二、Golang对UDP协议的支持

Golang作为一门高效的语言,对网络编程的支持也很强大。它内置了对TCP和UDP协议的支持,并且提供了方便易用的API。

对于UDP协议,Golang提供了两种方式处理数据:

  • PacketConn:基于数据包的方式传输UDP数据
  • Conn:基于流的方式传输UDP数据

三、PacketConn方式的使用

PacketConn方式是以数据包(Packet)的形式传输UDP数据。它相对于Conn方式更加简单直接,对于简单应用场景非常适合。

1、服务端代码示例

  package main

  import (
      "fmt"
      "net"
  )

  func main() {
      // 监听本地的UDP流量
      address, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
      if err != nil {
          fmt.Println(err)
      }

      conn, err := net.ListenUDP("udp", address)
      if err != nil {
          fmt.Println(err)
      }

      // 读取数据
      buffer := make([]byte, 1024)
      _, clientAddress, err := conn.ReadFromUDP(buffer)
      if err != nil {
          fmt.Println(err)
      }

      fmt.Printf("Received: %s from %s\n", buffer, clientAddress.String())

      // 发送数据
      _, err = conn.WriteToUDP([]byte("Hello, Client!"), clientAddress)
      if err != nil {
          fmt.Println(err)
      }

      // 关闭连接
      err = conn.Close()
      if err != nil {
          fmt.Println(err)
      }
  }

2、客户端代码示例

  package main

  import (
      "fmt"
      "net"
  )

  func main() {
      // 连接服务器
      serverAddress, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
      if err != nil {
          fmt.Println(err)
      }

      conn, err := net.DialUDP("udp", nil, serverAddress)
      if err != nil {
          fmt.Println(err)
      }

      // 发送数据
      data := []byte("Hello, Server!")
      _, err = conn.Write(data)
      if err != nil {
          fmt.Println(err)
      }

      // 接收数据
      buffer := make([]byte, 1024)
      _, err = conn.Read(buffer)
      if err != nil {
          fmt.Println(err)
      }

      fmt.Printf("Received: %s\n", buffer)

      // 关闭连接
      err = conn.Close()
      if err != nil {
          fmt.Println(err)
      }
  }

四、Conn方式的使用

Conn方式是以流的形式传输UDP数据。它相对于PacketConn方式更加灵活,可以处理更复杂的业务场景。

1、服务端代码示例

  package main

  import (
      "fmt"
      "net"
  )

  func main() {
      // 监听本地的UDP流量
      address, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
      if err != nil {
          fmt.Println(err)
      }

      conn, err := net.ListenUDP("udp", address)
      if err != nil {
          fmt.Println(err)
      }

      for {
          // 读取数据
          buffer := make([]byte, 1024)
          _, clientAddress, err := conn.ReadFromUDP(buffer)
          if err != nil {
              fmt.Println(err)
          }

          fmt.Printf("Received: %s from %s\n", buffer, clientAddress.String())

          // 发送数据
          _, err = conn.WriteToUDP([]byte("Hello, Client!"), clientAddress)
          if err != nil {
              fmt.Println(err)
          }
      }
  }

2、客户端代码示例

  package main

  import (
      "fmt"
      "net"
  )

  func main() {
      // 连接服务器
      serverAddress, err := net.ResolveUDPAddr("udp", "127.0.0.1:9876")
      if err != nil {
          fmt.Println(err)
      }

      conn, err := net.DialUDP("udp", nil, serverAddress)
      if err != nil {
          fmt.Println(err)
      }

      // 发送数据
      data := []byte("Hello, Server!")
      _, err = conn.Write(data)
      if err != nil {
          fmt.Println(err)
      }

      // 接收数据
      buffer := make([]byte, 1024)
      _, err = conn.Read(buffer)
      if err != nil {
          fmt.Println(err)
      }

      fmt.Printf("Received: %s\n", buffer)
  }

五、总结

Golang对于UDP协议的支持非常强大,并且使用方便。在实际的项目中,可以根据业务场景选择不同的方式来处理UDP数据。