Dart Datagram
最后修改于 2025 年 4 月 4 日
Dart 中的 Datagram 类代表用于网络通信的 UDP 数据报包。它与 RawDatagramSocket 一起用于发送和接收 UDP 数据包。
Datagram 同时包含数据负载和寻址信息。它是 Dart dart:io 库的一部分,用于底层网络操作。
基本定义
Datagram 是一个表示 UDP 数据包的不可变对象。它包含数据字节以及发送者/接收者的 InternetAddress 和端口。
主要属性包括数据访问、地址信息和端口号。UDP 是无连接的,不保证传输或顺序。
基本的 Datagram 接收器
此示例显示了如何在本地端口上接收 UDP 数据报。
import 'dart:io';
import 'dart:convert';
void main() async {
var socket = await RawDatagramSocket.bind('127.0.0.1', 3000);
print('UDP receiver listening on ${socket.address.address}:${socket.port}');
socket.listen((event) {
if (event == RawSocketEvent.read) {
Datagram? dg = socket.receive();
if (dg != null) {
String message = utf8.decode(dg.data);
print('Received from ${dg.address.address}:${dg.port} - $message');
}
}
});
}
我们将一个套接字绑定到 localhost 的 3000 端口,并监听传入的数据报。当数据到达时,我们将字节解码为 UTF-8,并打印消息及发送者详细信息。
$ dart receiver.dart UDP receiver listening on 127.0.0.1:3000 Received from 127.0.0.1:54321 - Hello UDP!
基本的 Datagram 发送器
此示例演示了如何将 UDP 数据报发送到接收器。
import 'dart:io';
import 'dart:convert';
void main() async {
var socket = await RawDatagramSocket.bind('127.0.0.1', 0); // Random port
var message = 'Hello UDP!';
var bytes = utf8.encode(message);
var sent = socket.send(
bytes,
InternetAddress('127.0.0.1'),
3000
);
print('Sent $sent bytes to port 3000');
await Future.delayed(Duration(seconds: 1)); // Wait for delivery
socket.close();
}
我们创建一个绑定到随机端口的套接字,将我们的消息编码为字节,并将其发送到端口 3000 上的接收器。send 方法返回已发送的字节数。
$ dart sender.dart Sent 10 bytes to port 3000
处理二进制数据
此示例显示了如何在 UDP 数据报中发送和接收二进制数据。
import 'dart:io';
import 'dart:typed_data';
void main() async {
var socket = await RawDatagramSocket.bind('127.0.0.1', 0);
// Create binary data (4 bytes representing 32-bit integer)
var buffer = ByteData(4);
buffer.setUint32(0, 0xDEADBEEF, Endian.big);
socket.send(
buffer.buffer.asUint8List(),
InternetAddress('127.0.0.1'),
3000
);
print('Sent binary data');
await Future.delayed(Duration(seconds: 1));
socket.close();
}
import 'dart:io';
import 'dart:typed_data';
void main() async {
var socket = await RawDatagramSocket.bind('127.0.0.1', 3000);
socket.listen((event) {
if (event == RawSocketEvent.read) {
Datagram? dg = socket.receive();
if (dg != null) {
var data = ByteData.sublistView(dg.data);
var value = data.getUint32(0, Endian.big);
print('Received 32-bit value: 0x${value.toRadixString(16)}');
}
}
});
}
发送器以大端序格式创建一个 32 位整数,并将其作为二进制数据发送。接收器从接收到的字节中重构整数并打印它。
$ dart binary_receiver.dart Received 32-bit value: 0xdeadbeef
广播 Datagram
此示例演示了 UDP 广播到多个接收器。
import 'dart:io';
import 'dart:convert';
void main() async {
var socket = await RawDatagramSocket.bind('0.0.0.0', 0);
socket.broadcastEnabled = true;
var message = 'Broadcast message!';
var bytes = utf8.encode(message);
socket.send(
bytes,
InternetAddress('255.255.255.255'),
3000
);
print('Broadcast sent');
await Future.delayed(Duration(seconds: 1));
socket.close();
}
我们在套接字上启用广播,并发送到有限广播地址。本地网络段上监听端口 3000 的所有主机将接收此数据报。
$ dart broadcast_sender.dart Broadcast sent
处理大型 Datagram
此示例显示了如何处理大于典型 MTU 的数据报。
import 'dart:io';
import 'dart:typed_data';
void main() async {
// Receiver
var receiver = await RawDatagramSocket.bind('127.0.0.1', 3000);
receiver.listen((event) {
if (event == RawSocketEvent.read) {
Datagram? dg = receiver.receive();
if (dg != null) {
print('Received ${dg.data.length} bytes');
}
}
});
// Sender
var sender = await RawDatagramSocket.bind('127.0.0.1', 0);
var largeData = Uint8List(65507); // Max safe UDP payload size
// Fill with some data
for (int i = 0; i < largeData.length; i++) {
largeData[i] = i % 256;
}
var sent = sender.send(
largeData,
InternetAddress('127.0.0.1'),
3000
);
print('Sent $sent bytes');
await Future.delayed(Duration(seconds: 2));
sender.close();
receiver.close();
}
我们创建了一个具有最大安全 UDP 有效负载大小(65,507 字节)的数据报。接收器仅报告接收数据的字节数。请注意,大型数据报可能会被 IP 层分片。
$ dart large_datagrams.dart Sent 65507 bytes Received 65507 bytes
最佳实践
- 错误处理:接收数据报时请务必检查 null
- MTU 感知:为获得最佳可靠性,请将数据报保持在 1500 字节以下
- 端口选择:用户应用程序请使用 1024 以上的端口
- 资源清理:使用完毕后关闭套接字以释放资源
- 超时处理:为预期响应实现超时
来源
本教程介绍了 Dart 的 Datagram 类,并提供了实用示例,展示了 UDP 通信、二进制数据处理、广播和大型有效负载。
作者
列出 所有 Dart 教程。