UDP 服务器和客户端开发

2.3 UDP 服务器和客户端开发

UDP 协议是非面向连接

UDP 其实是一种不可靠的协议,它在发送的时候不管客户端是否存在,也不管数据是否真的发送给了客户端。在工作中常见的 UDP 协议一般都是 DNS 在使用

在 UDP 种服务端开发和客户端开发都和 TCP 一样的。三个最主要的因素都是地址和协议还有链接

在 UDP 开发种没有监听

// 开启 UDP 链接
func net.ListenPacket(network string, address string) (net.PacketConn, error)

// 读取数据
func (net.PacketConn).ReadFrom(p []byte) (n int, addr net.Addr, err error)

2.3.1 服务器端不回复客户端消息范例

服务器端代码

package main

import (
    "fmt"
    "net"
)

func main() {
    // 监听所有网卡的 8888 端口
    addr := ":8888"

    // 协议使用 udp
    protocol := "udp"

    // 启动 UDP 链接
    packetConn, err := net.ListenPacket(protocol, addr)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 处理客户端
    // 通过 for 循环不断开连接读取客户端发来的数据,每次读取 1024 字节
    for {
        ctx := make([]byte, 1024)

        // 读取数据的时候肯定是需要知道从谁读取的,我们肯定需要告诉服务器端吧
        n, addr, err := packetConn.ReadFrom(ctx)
        if err != nil {
            fmt.Println(err)
            continue
        }

        // 输出 客户端 发送的数据
        fmt.Printf("客户端[%s]发送数据:%s\n", addr, string(ctx[:n]))
    }

    // 关闭服务器端
    packetConn.Close()
}

客户端代码

package main

import (
    "fmt"
    "net"
    "time"
)

func main() {
    addr := "127.0.0.1:8888"
    protocol := "udp"

    // UDP 客户端链接 server 端也是使用 net.Dial()
    conn, err := net.Dial(protocol, addr)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 客户端往服务器端发送数据
    n, err := conn.Write([]byte(time.Now().Format("2006-01-02 15:04:05")))
    fmt.Println(n, err)

    // 接收服务器端发送数据,因为 read 需要接收一个 []byte, 所以定义 cxt 的字节切皮变量
    cxt := make([]byte, 1024)

    // read 类似于一个寄存器,不接收到的数据寄存在 cxt 切片中,获取接收到的数据长度
    n, err = conn.Read(cxt)
    fmt.Printf("服务器端发送数据:%s\n", string(cxt[:n]))

    // 关闭连接
    conn.Close()
}
  1. 我们直接运行客户端

[17:47:26 root@go UDP]#go run client.go 
21 <nil>

# 通过运行我们会发现即使没有启动 server 端,客户端也不会报错
# 因为 UDP 协议中客户端发送数据的时候并不会关心服务器端是否真的存在

  1. 接着我们这次先启动服务器端

    1. 先启动 server 端

    2. 在启动 client 端

但是这个时候服务器端并不能向客户端回复消息。所以还的优化 server 端代码

2.3.2 server 端向客户端回复消息范例

server 端需要向 客户端 回复消息要使用到 net.WriteTo()方法,而且我们只需要修改 server 代码即可

[18:04:13 root@go UDP]#go doc net.writeTo
package net // import "net"

func (v *Buffers) WriteTo(w io.Writer) (n int64, err error)
func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error)
    WriteTo implements the PacketConn WriteTo method.

# 通过查看 go doc net.WriteTo() 方法是有两个参数一个是写入的字节切,一个是回复地址
func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error)
    WriteTo implements the PacketConn WriteTo method.

func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error)
    WriteTo implements the PacketConn WriteTo method.

server 端代码

package main

import (
    "fmt"
    "net"
)

func main() {
    // 监听所有网卡的 8888 端口
    addr := ":8888"

    // 协议使用 udp
    protocol := "udp"

    // 启动 UDP 链接
    packetConn, err := net.ListenPacket(protocol, addr)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 处理客户端
    // 通过 for 循环读取数据,每次读取 1024 字节
    for {
        ctx := make([]byte, 1024)

        // 读取数据的时候肯定是需要知道从谁读取的,我们肯定需要告诉服务器端吧
        n, addr, err := packetConn.ReadFrom(ctx)
        if err != nil {
            fmt.Println(err)
            continue
        }

        // 输出 客户端 发送的数据
        fmt.Printf("客户端[%s]发送数据:%s\n", addr, string(ctx[:n]))

        // 服务器端向客户端发送数据"我是服务器"
        fmt.Println(packetConn.WriteTo([]byte(string("我是服务器")), addr))
    }

    // 关闭服务器端
    packetConn.Close()
}

通过执行 server 端程序,而且 客户端未接收也不会报错,这个就是 UDP 和 TCP 协议之间的区别。

UDP 服务器端在发送数据的时候不会管客户端是否接收到

  1. 执行服务器端

  2. 执行客户端

  3. 客户端接收到了服务器端发送的数据

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇