【问题标题】:Constructing a line based ByteBuffer from an uint8List on-line在线从 uint8List 构造基于行的 ByteBuffer
【发布时间】:2020-01-03 14:56:38
【问题描述】:

我想我的问题很简单,但我是飞镖新手...

情况

  • 在客户端,我有一个打开的套接字,正在监听。
  • 服务器发送任意长度的数据块(实际上每个块在 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 分隔在另一个缓冲区(字节缓冲区列表)中。
数据会更容易处理(为解析器提供数据),而且我可以更早地更新前端。

问题

  • 我想在线处理数据(到达时)。这就是为什么我迫不及待地等待全部数据进来
  • 一个块可能有超过 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]

【问题讨论】:

    标签: sockets dart buffer


    【解决方案1】:

    我知道我建议的解决方案不能 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 类使用)转换为由Utf8Decoder 使用的普通List .我希望这在未来的 Dart 版本中是不必要的,因为它看起来有点傻。

    然后我将接收到的字节转换为 UTF8 并将其发送到 LineSplitter,它会从块中返回行。

    所有这些都在接收到数据时起作用。所以你的listen 方法会在每次解析完一整行时触发。

    同样,这并不完全如您所愿。但我希望它能给一个可行的解决方案带来一些启发。如果您想根据您的要求制作更具体的内容,您可以查看如何制作自己的 StreamTransformer

    【讨论】:

    • 感谢您的回答。我不知道 StreamTransformer 的事情。我想我最终会自己编写词法分析器部分,因为 LineSplitter() 不能以任何方式配置,这使得它对我的意图毫无用处。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多