首发原文链接: Swoole与Go系列教程之UDP服务的应用
大家好,我是码农先森。
写在前面
UDP协议相对于TCP协议而言,设计更为简单,不需要进行连接建立和断开的握手过程,也没有复杂的连接状态管理和流量控制机制。UDP协议的出现是为了满足特定类型的网络应用需求,如实时性要求高、可靠性要求低、数据传输速度要求快的场景。通过简化传输层功能和减少传输开销,UDP协议为这些应用提供了一种高效、快速的数据传输选择。
UDP 协议原理
UDP(User Datagram Protocol,用户数据报协议)是一种在计算机网络中常用的传输协议。与TCP协议相比,UDP是一种非连接型的协议,它在传输过程中不维护连接状态。UDP协议不需要在发送数据之前建立连接。每个UDP数据包(也称为数据报)都是独立的,可以独立地从源主机发送到目标主机。不提供可靠性保证,因此数据包的传输可能会丢失、损坏或以不同的顺序到达目标主机。数据包由固定大小的报头和有效负载组成。报头包含源端口号和目标端口号等信息,有效负载包含要传输的实际数据。
- 源端口(Source Port):是指发送端使用的端口号。它是UDP数据报文头部的一个字段,用于标识发送端应用程序或进程所使用的端口。
- 目的端口(Destination Port):是指接收端应用程序或进程等待接收UDP数据报的端口号。
- 长度(Length):是指UDP数据报的总长度,它包括了UDP报文头部和数据部分的长度之和。
- 校验和(Checksum):是一种用于检测数据在传输过程中是否出现错误或损坏的机制。它用于验证接收到的UDP数据报的完整性。
在 Swoole 中的应用
- 创建 UDP 服务对象需要指定
SWOOLE_SOCK_UDP
参数。 - 运行前设置进程的数量为 4,使用多进程模式。
- 使用
$server->on('Packet', function ($server, $data, $clientInfo){...}
接收客户端的事件。 - 然后使用
$server->sendto()
方法给客户端回复数据。 - 最后使用
$server->start();
启动服务,开始监听。 - 相较于 TCP 这里不需要建立连接,则可以直接接收事件。
<?php
// 创建 UDP 服务对象
$server = new Swoole\Server('0.0.0.0', 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
// 设置服务器运行时的参数
$server->set([
'worker_num' => 4,
]);
// 监听数据接收事件
$server->on('Packet', function ($server, $data, $clientInfo) {
echo "Received data from {$clientInfo['address']}:{$clientInfo['port']}: {$data}\n";
// 发送响应数据给客户端
$server->sendto($clientInfo['address'], $clientInfo['port'], 'Hello from Swoole server!');
});
// 启动服务器
$server->start();
在 Go 语言中的应用
- 使用
net.ListenPacket
创建 UDP 服务。 - 使用
conn.ReadFrom()
方法将客户端数据读入buffer
中。 - 最后,使用
conn.WriteTo
回复客户端数据。 - 这里在处理客户端数据时,也可以直接启用一个协程来处理提高效率。
package main
import (
"fmt"
"net"
)
func main() {
// 监听的地址和端口号
addr := "127.0.0.1:8888"
// 创建 UDP 监听器
conn, err := net.ListenPacket("udp", addr)
if err != nil {
fmt.Printf("Failed to listen: %v", err)
return
}
defer conn.Close()
fmt.Printf("Listening on %s\n", addr)
buffer := make([]byte, 1024)
for {
// 接收数据
n, addr, err := conn.ReadFrom(buffer)
if err != nil {
fmt.Printf("Failed to read from connection: %v", err)
break
}
fmt.Printf("Received data from %s: %s\n", addr.String(), string(buffer[:n]))
// 发送响应
_, err = conn.WriteTo([]byte("Response"), addr)
if err != nil {
fmt.Printf("Failed to write to connection: %v", err)
break
}
}
}
总结
- UDP 协议是一种高效、快速传输的协议。
- 该协议不用进行握手,即可直接发送数据。
- 在使用方式上 Swoole 和 Go 其实差别并不大。
- 不过 Swoole 是基于回调函数进行编程的,在实现风格上有不同。
- Go 语言对编程方式上会更加的简洁、方便。