sockets - 在线从 uint8List 构造基于行的 ByteBuffer
问题描述
我想我的问题很简单,但我是飞镖新手......
情况
- 在客户端,我有一个打开的套接字,正在监听。
- 服务器发送任意长度的数据块(实际上每个块在 2 到 1024 字节之间)
- 每次新数据到达时,它都会被添加到列表中(uint8List)
- 连接可能会长时间保持打开状态,并且可能会有“大量”数据块进入
这只是基本代码和工作。
main() async {
await SecureSocket.connect('SERVER', 123).then(handleResponse);
}
void handleResponse(SecureSocket ss) {
print('Connected to: '
'${ss.remoteAddress.address}:${ss.remotePort}');
ss.listen(
(data) {
print ('New chunk available:' + data.lengthInBytes.toString() + ' Bytes');
String msg = String.fromCharCodes(data).trim();
print(data.toString());
},
onDone: () {
ss.destroy();
},
onError: (error) {
print('An Error occured while communicating with the server.');
},
cancelOnError: true,
);
ss.write('FGG1223' + '\r\n');
}
现在,我想用传入的数据逐步更新我的前端。这就是为什么我想在数据到达后立即开始解析和处理数据。
从语义的角度来看,数据中的分隔符是CRLF [13,10]。
它将命令序列彼此分开,例如:
CMD1CMD2CRLFCMD3CRLF
因此,我的想法是将到达的数据基于行存储,由 CRLF 分隔在另一个缓冲区(ByteBuffer List)中。
数据会更容易处理(为解析器提供数据),而且我可以更早地更新前端。
问题
- 我想在线处理数据(到达时)。这就是为什么我不能等待整个数据进来
- 一个块可能有超过 1 个分隔符序列(参见示例响应 0)
- 定界符序列 (CRLF) 可以在 2 个或更多响应之间拆分(参见示例响应 1 和 2)
在这种情况下,我必须等到下一个 LF 到达下一个块之一,或者如果 LF 在 n 个块之后没有到达,则抛出异常。
在 dart 中是否有一种简单而优雅的方法来实现这一点?
谢谢你。
时间 0,1,2 的示例服务器响应: 0
块:[ 32,79,101,97,100,13,10,121,46,13,10 ] 1
块:[ 70,76,65,71,13 ]
2 块:[ 10 , 66, 89, 69, 32, 13 , 10 ]
解决方案
我知道我建议的解决方案不能 100% 符合您的要求,但我希望它仍然能给解决方案带来一些启发。我没有编写处理数据块拆分的所有逻辑,而是使用 Dart SDK 中的方法制作了这个示例:
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
await SecureSocket.connect('SERVER', 123).then(handleResponse);
}
void handleResponse(SecureSocket ss) {
print('Connected to: ${ss.remoteAddress.address}:${ss.remotePort}');
ss
.map((uint8list) => uint8list.toList())
.transform(const Utf8Decoder())
.transform(const LineSplitter())
.listen(
(line) {
print('New line available:' + line);
},
onDone: () {
ss.destroy();
},
onError: (Exception error) {
print('An Error occured while communicating with the server.');
},
cancelOnError: true,
);
ss.write('FGG1223\r\n');
}
首先,我要注意,该map
方法的使用用于将Uint8List
(由SecureSocket
类使用)转换List
为由Utf8Decoder
. 我希望这在未来的 Dart 版本中是不必要的,因为它看起来有点傻。
然后我将接收到的字节转换为 UTF8 并将其发送到LineSplitter
从块中返回行的 a。
所有这些都在接收到数据时起作用。因此,listen
每次解析整行时都会触发您的方法。
同样,这并不完全像您想要的那样。但我希望它能给一个可行的解决方案带来一些启发。如果您想根据您的要求制作更具体的东西,您可以查看如何制作自己的StreamTransformer
.
推荐阅读
- xml - 如何将xml中的requiredValue设置为任何值
- angular - 角度将图像传递给组件
- python - 在 python 中解析其 img 链接的 URL
- mysql - 如何计算日期错误之间的时间?
- c# - 如何访问主类之外的 WPF 控件属性
- javascript - $ 不是 wordpress 5.3 更新后的功能
- android - SQLITE:显示三个表差异与两个条件之间的差异
- javascript - 有没有更好的方法在两个单独的元素上运行这个函数?
- jq - jq:错误:语法错误,意外的 INVALID_CHARACTER,期待 $end(Unix shell 引用问题?)在
,第 1 行: - javascript - 从区域中取消附加 JQuery 拖放项目而不删除或隐藏它