Dart RawServerSocket
最后修改于 2025 年 4 月 4 日
Dart 中的 RawServerSocket 类提供了低级的 TCP 服务器套接字功能。它是 Dart 的 dart:io 库的一部分,用于非 Web 应用程序。
RawServerSocket 允许与 TCP 客户端进行直接的字节级通信。它适用于自定义协议、性能关键型应用程序和二进制数据。
基本定义
RawServerSocket 是一个服务器端套接字,用于监听传入的 TCP 连接。它提供原始字节流,不进行更高级别的协议处理。
主要功能包括异步操作、连接事件处理以及对套接字流的直接访问。它是构建自定义网络服务器的基础。
基本回显服务器
此示例展示了一个使用 RawServerSocket 的简单回显服务器。
import 'dart:io';
void main() async {
var server = await RawServerSocket.bind('127.0.0.1', 4040);
print('Echo server listening on ${server.address}:${server.port}');
server.listen((client) {
client.listen((data) {
client.add(data); // Echo back received data
}, onDone: () => client.close());
});
}
我们创建一个在 localhost 端口 4040 上监听的服务器。当客户端连接时,我们会将它们发送的任何数据回显回去。服务器异步处理多个客户端。
$ dart main.dart Echo server listening on 127.0.0.1:4040
处理客户端连接
此示例演示了详细的客户端连接处理。
import 'dart:io';
void main() async {
var server = await RawServerSocket.bind('0.0.0.0', 4041);
print('Server started on port ${server.port}');
server.listen((client) {
print('Client connected from ${client.remoteAddress.address}');
client.handleError((error) {
print('Client error: $error');
}, test: (error) => true);
client.listen((data) {
print('Received ${data.length} bytes');
client.add([0x01, 0x02, 0x03]); // Send response
}, onDone: () {
print('Client disconnected');
client.close();
});
});
}
我们记录客户端连接,处理错误,并发送固定响应。remoteAddress 属性用于标识连接的客户端。错误处理可确保服务器的稳定性。
$ dart main.dart Server started on port 4041 Client connected from 127.0.0.1 Received 5 bytes Client disconnected
广播服务器
此示例展示了一个将消息广播到所有连接客户端的服务器。
import 'dart:io';
import 'dart:async';
void main() async {
var server = await RawServerSocket.bind('127.0.0.1', 4042);
var clients = <RawSocket>[];
server.listen((client) {
clients.add(client);
print('New client (${clients.length} total)');
client.listen((_) {}, onDone: () {
clients.remove(client);
print('Client disconnected (${clients.length} remaining)');
});
});
// Broadcast timer
Timer.periodic(Duration(seconds: 2), (_) {
var message = 'Server time: ${DateTime.now()}\n'.codeUnits;
for (var client in clients) {
client.add(message);
}
});
}
我们维护一个已连接客户端列表,并每 2 秒广播一次时间更新。服务器跟踪客户端的连接和断开连接。
$ dart main.dart New client (1 total) New client (2 total) Client disconnected (1 remaining)
端口扫描器
此示例演示了如何使用 RawServerSocket 检查端口可用性。
import 'dart:io';
Future<bool> isPortAvailable(int port) async {
try {
var server = await RawServerSocket.bind('127.0.0.1', port);
await server.close();
return true;
} catch (e) {
return false;
}
}
void main() async {
var ports = [80, 4040, 8080, 3000];
for (var port in ports) {
var available = await isPortAvailable(port);
print('Port $port: ${available ? 'available' : 'in use'}');
}
}
我们尝试绑定到每个端口以检查可用性。成功绑定意味着该端口可用。服务器在检查后立即关闭。
$ dart main.dart Port 80: in use Port 4040: available Port 8080: in use Port 3000: available
自定义协议服务器
此示例实现了一个简单的自定义二进制协议服务器。
import 'dart:io';
void main() async {
var server = await RawServerSocket.bind('127.0.0.1', 4043);
print('Custom protocol server started');
server.listen((client) {
var buffer = <int>[];
client.listen((data) {
buffer.addAll(data);
// Process complete messages (delimited by 0xFF)
while (buffer.contains(0xFF)) {
var messageEnd = buffer.indexOf(0xFF);
var message = buffer.sublist(0, messageEnd);
buffer.removeRange(0, messageEnd + 1);
print('Received message: $message');
client.add([...message.reversed, 0xFF]); // Send reversed
}
}, onDone: () => client.close());
});
}
我们实现了一个简单的协议,其中消息以 0xFF 结尾。服务器处理完整的消息并以反转的数据响应。部分消息会被缓冲。
$ dart main.dart Custom protocol server started Received message: [72, 101, 108, 108, 111]
最佳实践
- 错误处理:始终为套接字实现错误处理程序
- 资源清理:完成后关闭套接字以释放资源
- 缓冲:通过适当的缓冲处理部分数据
- 背压:监控套接字写入缓冲区以避免过载
- 安全性:验证所有传入数据并限制连接
来源
本教程通过实际示例介绍了 Dart 的 RawServerSocket 类,展示了服务器创建、客户端处理和自定义协议实现。
作者
列出 所有 Dart 教程。