Dart RawDatagramSocket
最后修改于 2025 年 4 月 4 日
Dart 中的 RawDatagramSocket
类提供了 UDP 套接字功能。它允许通过 IP 网络发送和接收数据报(UDP 数据包)。
与 TCP 套接字不同,UDP 是无连接的,不保证送达。RawDatagramSocket 是 Dart dart:io
库的一部分,用于 I/O 操作。
基本定义
RawDatagramSocket
表示一个可以绑定到端口的 UDP 套接字。它支持 IPv4 和 IPv6 地址,并提供基于事件的 I/O。
主要功能包括发送/接收数据报、组播支持和端口绑定。它对于游戏和流媒体等低延迟应用程序非常有用。
基本的 UDP 回显服务器
此示例展示了一个简单的 UDP 回显服务器,它可以将接收到的数据包发送回去。
import 'dart:io'; void main() async { var socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 8888); print('UDP echo server listening on ${socket.address}:${socket.port}'); socket.listen((RawSocketEvent event) { if (event == RawSocketEvent.read) { var datagram = socket.receive(); if (datagram != null) { print('Received from ${datagram.address}:${datagram.port}'); socket.send(datagram.data, datagram.address, datagram.port); } } }); }
我们将服务器绑定到端口 8888 上的任何 IPv4 地址,并监听传入的数据报。当数据到达时,我们打印发送者信息并将数据回显回去。
$ dart main.dart UDP echo server listening on 0.0.0.0:8888 Received from 127.0.0.1:54321
UDP 客户端示例
此示例演示了一个向服务器发送消息的 UDP 客户端。
import 'dart:io'; void main() async { var socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); print('Client bound to port ${socket.port}'); var message = 'Hello UDP'; var data = message.codeUnits; var server = InternetAddress.loopbackIPv4; var port = 8888; socket.send(data, server, port); print('Sent "$message" to $server:$port'); socket.listen((event) { if (event == RawSocketEvent.read) { var datagram = socket.receive(); if (datagram != null) { print('Received: ${String.fromCharCodes(datagram.data)}'); } } }); }
客户端绑定到一个随机端口(0),将消息发送到服务器,然后等待响应。在通过 UDP 发送之前,我们将字符串转换为字节。
$ dart main.dart Client bound to port 54321 Sent "Hello UDP" to 127.0.0.1:8888 Received: Hello UDP
广播 UDP 数据包
此示例展示了如何将 UDP 广播数据包发送到网络上的所有主机。
import 'dart:io'; void main() async { var socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); socket.broadcastEnabled = true; var message = 'Broadcast message'; var data = message.codeUnits; var port = 8888; socket.send(data, InternetAddress('255.255.255.255'), port); print('Broadcast sent to port $port'); socket.close(); }
我们启用广播并将数据发送到特殊的广播地址 255.255.255.255。这将数据包发送到本地网络段上的所有主机。
$ dart main.dart Broadcast sent to port 8888
组播 UDP 示例
此示例演示了加入组播组并接收数据包。
import 'dart:io'; void main() async { var socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 8888); var multicast = InternetAddress('239.1.2.3'); socket.joinMulticast(multicast); print('Joined multicast group $multicast'); socket.listen((event) { if (event == RawSocketEvent.read) { var datagram = socket.receive(); if (datagram != null) { print('Multicast from ${datagram.address}: ${String.fromCharCodes(datagram.data)}'); } } }); }
我们加入组播组 239.1.2.3 并监听传入的数据包。组播允许在网络上进行高效的一对多通信。
$ dart main.dart Joined multicast group 239.1.2.3 Multicast from 192.168.1.100: Test multicast message
处理错误和超时
此示例展示了 UDP 套接字的错误处理和超时配置。
import 'dart:io'; import 'dart:async'; void main() async { try { var socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 8888) .timeout(Duration(seconds: 5)); socket.handleError((error) { print('Socket error: $error'); }); socket.listen((event) { if (event == RawSocketEvent.read) { var datagram = socket.receive(); print('Received data'); } if (event == RawSocketEvent.closed) { print('Socket closed'); } }); Timer(Duration(seconds: 10), () { socket.close(); }); } on TimeoutException { print('Failed to bind socket within 5 seconds'); } on SocketException catch (e) { print('Socket exception: ${e.message}'); } }
我们为套接字绑定添加超时、错误处理程序以及自动套接字关闭。这使得 UDP 通信在实际场景中更加健壮。
$ dart main.dart Socket closed
最佳实践
- 错误处理:始终为套接字实现错误处理程序
- 端口选择:在客户端中使用 0 表示临时端口
- 缓冲区大小:UDP 有 MTU 限制(通常为 1500 字节)
- 组播 TTL:为组播数据包设置适当的 TTL
- 资源清理:完成后关闭套接字
来源
本教程介绍了 Dart 的 RawDatagramSocket 类,并提供了实际示例,展示了包括单播、广播和组播在内的 UDP 通信模式。
作者
列出 所有 Dart 教程。