ZetCode

Dart Datagram

最后修改于 2025 年 4 月 4 日

Dart 中的 Datagram 类代表用于网络通信的 UDP 数据报包。它与 RawDatagramSocket 一起用于发送和接收 UDP 数据包。

Datagram 同时包含数据负载和寻址信息。它是 Dart dart:io 库的一部分,用于底层网络操作。

基本定义

Datagram 是一个表示 UDP 数据包的不可变对象。它包含数据字节以及发送者/接收者的 InternetAddress 和端口。

主要属性包括数据访问、地址信息和端口号。UDP 是无连接的,不保证传输或顺序。

基本的 Datagram 接收器

此示例显示了如何在本地端口上接收 UDP 数据报。

receiver.dart
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 数据报发送到接收器。

sender.dart
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 数据报中发送和接收二进制数据。

binary_sender.dart
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();
}
binary_receiver.dart
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 广播到多个接收器。

broadcast_sender.dart
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 的数据报。

large_datagrams.dart
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

最佳实践

来源

Dart Datagram 文档

本教程介绍了 Dart 的 Datagram 类,并提供了实用示例,展示了 UDP 通信、二进制数据处理、广播和大型有效负载。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程