Dart SocketMessage
最后修改于 2025 年 4 月 4 日
Dart 中的 SocketMessage 类提供了一种通过套接字处理网络通信的方式。它对于构建客户端-服务器应用程序和实时系统非常有用。
SocketMessage 管理消息帧、序列化和网络传输。它通常与 Dart 的 dart:io 库一起用于套接字编程。
基本定义
SocketMessage 代表套接字上传递的离散通信单元。它通常包含用于结构化数据的头部和有效载荷。
主要功能包括消息帧、二进制/字符串转换和错误处理。它有助于管理网络通信的复杂性。
基本的 SocketMessage 用法
此示例展示了通过套接字创建和发送基本消息。
import 'dart:io';
import 'dart:convert';
class SocketMessage {
final Map<String, String> headers;
final String body;
SocketMessage(this.headers, this.body);
List<int> toBytes() {
var headerStr = headers.entries
.map((e) => '${e.key}:${e.value}')
.join(';');
return utf8.encode('$headerStr|$body');
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4040);
print('Server listening on ${server.address}:${server.port}');
server.listen((client) {
client.transform(utf8.decoder).listen((data) {
print('Received: $data');
});
});
var client = await Socket.connect('127.0.0.1', 4040);
var message = SocketMessage(
{'type': 'greeting', 'length': '5'},
'Hello'
);
client.add(message.toBytes());
}
我们创建了一个带有头部和主体的简单 SocketMessage 类。服务器监听连接,而客户端发送格式化消息。消息被转换为字节进行传输。
$ dart main.dart Server listening on 127.0.0.1:4040 Received: type:greeting;length:5|Hello
处理二进制数据
此示例演示了 SocketMessage 中处理二进制数据。
import 'dart:io';
import 'dart:typed_data';
class BinarySocketMessage {
final int type;
final Uint8List data;
BinarySocketMessage(this.type, this.data);
Uint8List toBytes() {
var buffer = ByteData(4 + data.length);
buffer.setUint32(0, type);
buffer.buffer.asUint8List().setAll(4, data);
return buffer.buffer.asUint8List();
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((client) {
client.listen((data) {
var bytes = Uint8List.fromList(data);
var type = ByteData.sublistView(bytes, 0, 4).getUint32(0);
print('Received message type: $type');
});
});
var client = await Socket.connect('127.0.0.1', 4041);
var message = BinarySocketMessage(
42,
Uint8List.fromList([1, 2, 3, 4, 5])
);
client.add(message.toBytes());
}
我们创建了一个二进制消息格式,其头部是 4 字节的类型,后面跟着有效载荷。服务器从二进制数据中提取消息类型。这对于二进制协议来说效率很高。
$ dart main.dart Received message type: 42
消息帧
此示例展示了如何实现带长度前缀的消息帧。
import 'dart:io';
import 'dart:typed_data';
import 'dart:convert';
class FramedSocketMessage {
final String content;
FramedSocketMessage(this.content);
Uint8List toBytes() {
var contentBytes = utf8.encode(content);
var buffer = ByteData(4 + contentBytes.length);
buffer.setUint32(0, contentBytes.length);
buffer.buffer.asUint8List().setAll(4, contentBytes);
return buffer.buffer.asUint8List();
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4042);
server.listen((client) {
var buffer = <int>[];
client.listen((data) {
buffer.addAll(data);
if (buffer.length >= 4) {
var length = ByteData.sublistView(Uint8List.fromList(buffer), 0, 4)
.getUint32(0);
if (buffer.length >= 4 + length) {
var message = utf8.decode(buffer.sublist(4, 4 + length));
print('Framed message: $message');
buffer = buffer.sublist(4 + length);
}
}
});
});
var client = await Socket.connect('127.0.0.1', 4042);
var message = FramedSocketMessage('Hello, framed world!');
client.add(message.toBytes());
}
我们实现了带长度前缀的消息帧。消息以 4 字节的长度开头,后跟有效载荷。服务器首先读取长度,然后读取精确的有效载荷字节。这可以正确处理消息边界。
$ dart main.dart Framed message: Hello, framed world!
JSON 消息格式
此示例演示了使用 JSON 进行结构化消息内容。
import 'dart:io';
import 'dart:convert';
class JsonSocketMessage {
final String type;
final Map<String, dynamic> payload;
JsonSocketMessage(this.type, this.payload);
List<int> toBytes() {
var message = {
'type': type,
'payload': payload,
'timestamp': DateTime.now().toIso8601String()
};
return utf8.encode(json.encode(message));
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4043);
server.listen((client) {
client.transform(utf8.decoder).listen((data) {
var message = json.decode(data);
print('${message['type']}: ${message['payload']}');
});
});
var client = await Socket.connect('127.0.0.1', 4043);
var message = JsonSocketMessage(
'user.login',
{'username': 'johndoe', 'password': 'secret'}
);
client.add(message.toBytes());
}
我们创建了带有类型和有效载荷字段的 JSON 格式消息。服务器解码 JSON 并提取消息组件。这对于 Web API 和结构化通信很有用。
$ dart main.dart
user.login: {username: johndoe, password: secret}
错误处理
此示例展示了套接字消息处理中的强大错误处理。
import 'dart:io';
import 'dart:convert';
class SafeSocketMessage {
final String command;
final List<String> args;
SafeSocketMessage(this.command, this.args);
List<int> toBytes() {
try {
return utf8.encode('$command:${args.join(',')}');
} catch (e) {
return utf8.encode('error:Failed to encode message');
}
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4044);
server.listen((client) {
client.transform(utf8.decoder).listen(
(data) {
try {
var parts = data.split(':');
if (parts.length != 2) throw FormatException('Invalid format');
print('Command: ${parts[0]}, Args: ${parts[1].split(',')}');
} catch (e) {
print('Error processing message: $e');
client.write('error:Invalid message format');
}
},
onError: (e) => print('Connection error: $e'),
onDone: () => print('Client disconnected')
);
});
var client = await Socket.connect('127.0.0.1', 4044);
var message = SafeSocketMessage('calculate', ['add', '5', '3']);
client.add(message.toBytes());
client.listen((response) {
print('Server response: ${utf8.decode(response)}');
client.close();
});
}
我们在消息创建和处理阶段都实现了错误处理。客户端发送结构化的命令消息,而服务器对其进行验证。当出现问题时,会发送错误响应。
$ dart main.dart Command: calculate, Args: [add, 5, 3] Client disconnected
最佳实践
- 消息帧:始终实现正确的消息边界
- 错误处理:验证消息并优雅地处理错误
- 序列化:选择合适的格式(JSON、二进制等)
- 资源管理:正确关闭套接字
- 超时:为网络操作实现超时
来源
本教程介绍了 Dart 的 SocketMessage 模式,并提供了实际示例,展示了文本/二进制格式、消息帧、JSON 和错误处理,以实现健壮的网络通信。
作者
列出 所有 Dart 教程。