UDP通信-与TCP的差异-服务器与客户端-并发

未匹配的标注

UDP通信

UDP通信-与TCP的差异-服务器与客户端

在之前的案例中,我们一直使用的是TCP协议来编写Socket的客户端与服务端。其实也可以使用UDP协议来编写Socket的客户端与服务端。

UDP与TCP的差异

| TCP | UDP |
| 面向连接 | 面向无连接 |
| 要求系统资源较多 | 要求系统资源较少 |
| TCP程序结构较复杂 | UDP程序结构较简单 |
| 使用流式 | 使用数据报式 |
| 保证数据准确性 | 不保证数据准确性 |
| 保证数据顺序 | 不保证数据顺序 |
| 通讯速度较慢 | 通讯速度较快 |

UDP服务器

由于UDP是“无连接”的,所以,服务器端不需要额外创建监听套接字,只需要指定好IP和port,然后监听该地址,等待客户端与之建立连接,即可通信。

创建监听地址:
    func ResolveUDPAddr(network, address string) (*UDPAddr, error) 
创建用于通信的socket:
    func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) 
接收udp数据:
    func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error)
写出数据到udp:
    func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)

服务端完整代码实现如下:

package main

import (
   "fmt"
   "net"
)

func main() {
   //创建监听的地址,并且指定udp协议
   udp_addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8002")
   if err != nil {
      fmt.Println("ResolveUDPAddr err:", err)
      return
   }
   conn, err := net.ListenUDP("udp", udp_addr)    // 创建数据通信socket
   if err != nil {
      fmt.Println("ListenUDP err:", err)
      return
   }
   defer conn.Close()

   buf := make([]byte, 1024)
   n, raddr, err := conn.ReadFromUDP(buf)        //接收客户端发送过来的数据,填充到切片buf中。
   if err != nil {
      return
   }
   fmt.Println("客户端发送:", string(buf[:n]))

   _, err = conn.WriteToUDP([]byte("nice to see u in udp"), raddr) // 向客户端发送数据
   if err != nil {
      fmt.Println("WriteToUDP err:", err)
      return
   }
}

UDP客户端

udp客户端的编写与TCP客户端的编写,基本上是一样的,只是将协议换成udp。注意只能使用小写。

代码如下:

package main

import (
   "net"
   "fmt"
)

func main() {
   conn, err := net.Dial("udp", "127.0.0.1:8002") 
   if err != nil {
      fmt.Println("net.Dial err:", err)
      return
   }
   defer conn.Close()

   conn.Write([]byte("Hello! I'm client in UDP!"))

   buf := make([]byte, 1024)
   n, err1 := conn.Read(buf)
   if err1 != nil {
      return
   }
   fmt.Println("服务器发来:", string(buf[:n]))
}

并发

其实对于UDP而言,服务器不需要并发,只要循环处理客户端数据即可。客户端也等同于TCP通信并发的客户端。

服务器:

package main

import (
   "net"
   "fmt"
)

func main() {
   // 创建 服务器 UDP 地址结构。指定 IP + port
   laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8003")
   if err != nil {
      fmt.Println("ResolveUDPAddr err:", err)
      return
   }
   // 监听 客户端连接
   conn, err := net.ListenUDP("udp", laddr)
   if err != nil {
      fmt.Println("net.ListenUDP err:", err)
      return
   }
   defer conn.Close()

   for {
      buf := make([]byte, 1024)
      n, raddr, err := conn.ReadFromUDP(buf)
      if err != nil {
         fmt.Println("conn.ReadFromUDP err:", err)
         return
      }
      fmt.Printf("接收到客户端[%s]:%s", raddr, string(buf[:n]))

      conn.WriteToUDP([]byte("I-AM-SERVER"), raddr) // 简单回写数据给客户端
   }
}

客户端:

package main

import (
   "net"
   "os"
   "fmt"
)

func main() {
   conn, err := net.Dial("udp", "127.0.0.1:8003")
   if err != nil {
      fmt.Println("net.Dial err:", err)
      return
   }
   defer conn.Close()
   go func() {
      str := make([]byte, 1024)
      for {
         n, err := os.Stdin.Read(str) //从键盘读取内容, 放在str
         if err != nil {
            fmt.Println("os.Stdin. err1 = ", err)
            return
         }
         conn.Write(str[:n])       // 给服务器发送
      }
   }()
   buf := make([]byte, 1024)
   for {
      n, err := conn.Read(buf)
      if err != nil {
         fmt.Println("conn.Read err:", err)
         return
      }
      fmt.Println("服务器写来:", string(buf[:n]))
   }
}

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~