这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战
UDP
用户数据报协议. 属于ISO七层参考模型中的传输层. 它是无连接的, 不保证可靠传输
UDP特点
- 无连接, 因为不需要建立连接, 因此减少了开销和发送数据之前的时延
- 尽最大努力交付, 不保证可靠交付
- 面向报文, 传输数据报数据
- 支持一对一, 一对多和多对多通信
- 首部只有8个字节, 开销很小
基于UDP具有资源消耗小, 处理速度快的优点, 所以通常音频, 视频和普通数据在传送时使用UDP较多, 因为即使偶尔丢失一两个数据包, 也不会对接收结果产生太大影响.
UDP服务端流程
- 调用net.ListenUDP函数进行网络监听, 返回一个UDPConn实例
- 通过一个goroutine来处理该连接请求
- 当处理完成后, 可以选择调用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")
}
}
客户端流程
- 调用net.DialUDP函数建立连接, 返回一个Conn实例
- 通过一个goroutine来处理该连接请求
- 当处理完成后, 可以选择调用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)
}
}