Dart 的简单套接字库
一个用于处理 Dart 套接字器的简单库。
Dart 的 socket-io NodeJS 移植版 相当不错,但缺少类型定义,而且我不喜欢使用 dynamic 数据类型。此外,它相当臃肿,我不需要所有这些功能,我只想确保我有一个最小化的直观库,我可以在 Dart 套接字类之上进行工作,而无需担心内存泄漏,因为我忘记了打开的第 9 个 Stream 监听器。
当前实现的功能
- 支持服务器端。
- 支持客户端。
- 通过
sendAPI 进行消息帧处理。 - 完全类型的 API,尽管是可选的。
- 轻量级:代码行数少于 400 行。
- 事件驱动的回调。
- 自定义事件类型。
基本用法
final SimpleServerSocket server = await SimpleServerSocket.bind();
server.on<SimpleSocket>('connection', (SimpleSocket client) {
// or: client.sendMessage('hello', 'Hi, client.');
client.sendSignal('hello');
client.on<void>('bye', (_) => server.destroy());
});
server.listen();
// On client-side:
final SimpleSocket socket =
await SimpleSocket.connect('localhost', server.port);
socket.on<void>('hello', (_) => socket.replyWithSignal('bye'));
使用消息
final SimpleServerSocket server = await SimpleServerSocket.bind();
server.on<SimpleSocket>('connection', (SimpleSocket client) {
client.sendMessage('greetings', 'Sup client!');
client.on<List<int>>('bye', (List<int> data) {
print(String.fromCharCodes(data)); // Bye bye...
server.destroy();
});
});
server.listen();
// On client-side:
final SimpleSocket socket =
await SimpleSocket.connect('localhost', server.port);
socket.on<List<int>>('greetings', (List<int> data) {
print(String.fromCharCodes(data)); // Sup client!
socket.reply('bye', 'Bye bye...');
});
这就是使用原始 Dart 套接字进行工作的样子。
final ServerSocket server =
await ServerSocket.bind(InternetAddress.anyIPv4, 0);
late final StreamSubscription<Socket> onNewClientListener;
Future<void> closeServer() async {
await onNewClientListener.cancel();
await server.close();
}
onNewClientListener = server.listen(
(Socket client) {
late final StreamSubscription<String> onNewMessageListener;
Future<void> cancelListener() async {
await onNewMessageListener.cancel();
}
client.write('Sup client!');
onNewMessageListener = client.map(String.fromCharCodes).listen(
// No TCP messaging-frame support!
(String message) {
print(message);
if (message == 'bye') {
client.close();
closeServer();
}
},
cancelOnError: true,
onDone: cancelListener,
onError: (_) => cancelListener(),
);
},
cancelOnError: true,
onDone: closeServer,
onError: (_) => closeServer(),
);
// On client-side.
final Socket socket = await Socket.connect('localhost', server.port);
late final StreamSubscription<String> onNewServerMessageListener;
Future<void> cancelListener() async {
socket.destroy();
await socket.close();
await onNewServerMessageListener.cancel();
}
onNewServerMessageListener = socket.map(String.fromCharCodes).listen(
// No TCP messaging-frame support!
(String message) {
if (message.startsWith('Sup')) {
print(message);
socket.write('bye');
}
},
cancelOnError: true,
onDone: cancelListener,
onError: (_) => cancelListener(),
);
进一步阅读
- 消息帧处理 – https://blog.stephencleary.com/2009/04/message-framing.html。
- 如何为流创建 TCP 消息帧 – https://stackoverflow.com/questions/47382549/how-to-create-tcp-message-framing-for-the-stream。
- Dart TCP 套接字将所有‘write’同步调用串联为一个数据包 – https://stackoverflow.com/questions/75314786/dart-tcp-socket-concatenates-all-write-sync-calls-as-a-single-packet。
开源
版权所有 © 2023-present, Alex Rintt。
Simple Socket 是 MIT 许可吗?