You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Flutter Completer串联Future实现Socket逐字节请求?

解决方案:用Completer实现逐字节发送+回显确认

你的思路是对的,用Completer可以精准控制发送节奏,避免Future.delayed的不确定性。原代码的问题主要在于Completer列表的索引管理容易混乱,以及字节的字符串比较逻辑不可靠,下面是修正后的实现方案:

核心调整点

  • 不再维护Completer列表,而是每次发送单个字节时创建一个临时Completer,等待回显后完成它
  • 直接比较字节数值而非字符串,避免格式差异导致的匹配失败
  • 用单独变量跟踪当前等待确认的Completer,而非依赖全局索引

修正后的代码示例

Completer<bool>? _currentAckCompleter;
int? _expectedByte; // 记录当前等待回显的字节值

@override
void send(dynamic data) async {
  if (data is! List<int>) {
    throw ArgumentError("data must be a list of bytes");
  }

  for (var byte in data) {
    final completer = Completer<bool>();
    _currentAckCompleter = completer;
    _expectedByte = byte;

    try {
      // 发送单个字节
      await _udpSocket.send([byte], ipAddress!, portNumber!);
      // 等待回显确认
      await completer.future;
    } catch (e) {
      // 发送或确认失败,终止后续发送并抛出异常
      _currentAckCompleter = null;
      _expectedByte = null;
      rethrow;
    } finally {
      // 清理当前状态
      _currentAckCompleter = null;
      _expectedByte = null;
    }
  }
}

@override
Future<bool> connect() async {
  // ... 原有的连接逻辑 ...
  reader.listen((Uint8List data) {
    // 假设回显是单个字节,取第一个字节判断
    if (data.isNotEmpty && _expectedByte != null && data[0] == _expectedByte) {
      _currentAckCompleter?.complete(true);
    }

    // 原有的缓冲区处理逻辑保留
    buffer.addAll(data);
    controller.sink.add(buffer.sublist(0, buffer.length - 2));
  });
  // ... 原有的连接成功返回逻辑 ...
  return true;
}

额外建议

  • 超时处理:如果长时间未收到回显,建议添加超时逻辑,避免无限等待:
    // 在send方法的await completer.future处替换为:
    await Future.any([
      completer.future,
      Future.delayed(const Duration(seconds: 5)).then((_) => throw TimeoutException("Ack timeout"))
    ]);
    
  • UDP可靠性优化:UDP本身无连接不可靠,若场景要求必达,建议在应用层添加重传机制,比如确认超时后重新发送当前字节
  • 并发安全:如果存在多个并发send请求,需要加锁或队列处理,避免状态混乱

内容的提问来源于stack exchange,提问作者saguado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:13:39