Go中的UDP

276 阅读2分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

UDP

用户数据报协议. 属于ISO七层参考模型中的传输层. 它是无连接的, 不保证可靠传输

UDP特点

  1. 无连接, 因为不需要建立连接, 因此减少了开销和发送数据之前的时延
  2. 尽最大努力交付, 不保证可靠交付
  3. 面向报文, 传输数据报数据
  4. 支持一对一, 一对多和多对多通信
  5. 首部只有8个字节, 开销很小

基于UDP具有资源消耗小, 处理速度快的优点, 所以通常音频, 视频和普通数据在传送时使用UDP较多, 因为即使偶尔丢失一两个数据包, 也不会对接收结果产生太大影响.

UDP服务端流程

  1. 调用net.ListenUDP函数进行网络监听, 返回一个UDPConn实例
  2. 通过一个goroutine来处理该连接请求
  3. 当处理完成后, 可以选择调用Close方法来关闭该连接

UDP服务端代码

 import (
    "fmt"
    "net"
 )
 ​
 func main() {
    // 创建一个UDP地址 ip为: 127.0.0.1, 端口号为: 2000
    addr := net.UDPAddr{
       IP:   net.IPv4(127, 0, 0, 1),
       Port: 2000,
    }
 ​
    // 进行UDP的监听
    uconn, err := net.ListenUDP("udp", &addr)
 ​
    // 监听失败, 输出错误信息
    if err != nil {
       fmt.Println("udp listen failed: ", err)
       return
    }
 ​
    // 监听成功
    fmt.Println("udp listen success")
 ​
    // 当退出程序时, 退出UDP的监听
    defer func() {
       fmt.Println("uconn closed")
       uconn.Close()
    }()
 ​
    // 处理监听到的数据
    dealConn(uconn)
 }
 ​
 func dealConn(uconn *net.UDPConn)  {
    // 读取数据
    for {
       data := make([]byte, 16)
 ​
       // 接收来自client发送过来的数据
       n, uaddr, err := uconn.ReadFromUDP(data)
 ​
       // 读取数据失败, 输出错误信息
       if err != nil {
          fmt.Println("udp read failed: ", err)
          continue
       }
 ​
       // 读取数据成功
       fmt.Println("udp read success: ", string(data[:n]))
       fmt.Println("uaddr: ", uaddr)
 ​
       // 向client发送响应数据
       n, err = uconn.WriteToUDP(data[:n], uaddr)
 ​
       // 向client发送数据失败
       if err != nil {
          fmt.Println("udp write failed: ", err)
          continue
       }
 ​
       // 向client发送数据成功
       fmt.Println("udp write success")
    }
 }

客户端流程

  1. 调用net.DialUDP函数建立连接, 返回一个Conn实例
  2. 通过一个goroutine来处理该连接请求
  3. 当处理完成后, 可以选择调用Close方法来关闭该连接

UDP客户端代码

 import (
    "bufio"
    "fmt"
    "net"
    "os"
    "strings"
 )
 ​
 func main() {
    // 创建一个要请求的UDP地址
    addr := net.UDPAddr{
       IP:   net.IPv4(127, 0, 0, 1),
       Port: 2000,
    }
 ​
    // 连接server端
    uconn, err := net.DialUDP("udp", nil, &addr)
 ​
    // 连接失败, 退出程序
    if err != nil {
       fmt.Println("udp dial failed: ", err)
       return
    }
 ​
    // 连接成功
    fmt.Println("udp dial success")
   
     // 关闭连接
     defer func() {
       fmt.Println("udp closed!")
       uconn.Close()
     }()
 ​
    // 进行UDP请求
    requestUDP(uconn)
 }
 ​
 func requestUDP(uconn *net.UDPConn) {
    reader := bufio.NewReader(os.Stdin)
 ​
    for {
       // 接收从键盘输入的数据
       data, err := reader.ReadString('\n')
       sendData := strings.Trim(data, "\n")
 ​
       // 如果为Q退出程序
       if strings.ToUpper(sendData) == "Q" {
          break
       }
 ​
       // 向server端发送数据
       _, err = uconn.Write([]byte(sendData))
 ​
       // 发送数据失败
       if err != nil {
          fmt.Println("udp write failed: ", err)
       }
 ​
       // 发送数据成功
       fmt.Println("udp write success")
 ​
       // 从server接收数据
       serverData := make([]byte, 16)
 ​
       // 接收来自server的响应
       n, uaddr, err := uconn.ReadFromUDP(serverData)
       if err != nil {
          fmt.Println("client recv failed")
       }
       fmt.Println("client recv success: ", string(serverData[:n]))
       fmt.Println("addr: ", uaddr)
    }
 }