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

Flutter中TCP连接接收数据返回遇Future已完成错误的解决咨询

问题分析

你遇到的"Future already completed"错误,核心原因是**Completer被多次调用complete方法**。结合你的控制台输出,触发场景主要有两种:

  1. 设备返回的数据被TCP拆分为多个数据包,socket.listen的回调被多次执行,每次都尝试完成已完成的completer
  2. 虽然socket已收到数据并完成completer,但后续的onDone或onError回调仍尝试调用completer.complete

另外控制台同时输出设备数据和Timeout,说明超时逻辑与socket数据接收存在时序冲突——不必要的延迟可能导致命令发送时机过晚,超时倒计时提前启动,进而引发后续异常。

修复后的代码
Future<String?> sendAndReceiveCommand(String value) async {
  Socket? socket;
  StreamSubscription? subscription;
  final completer = Completer<String>();
  StringBuffer answerBuffer = StringBuffer();

  try {
    // 解析目标IP地址
    final ipParts = '192.168.4.1'.split('.').map((part) => int.parse(part)).toList();
    final ipAddress = InternetAddress.fromRawAddress(Uint8List.fromList(ipParts));

    // 建立TCP连接
    socket = await Socket.connect(ipAddress, 80, timeout: const Duration(seconds: 10));
    socket.setOption(SocketOption.tcpNoDelay, true);

    // 监听socket数据流
    subscription = socket.listen(
      (data) {
        final chunk = ascii.decode(data);
        answerBuffer.write(chunk);
        print('Received chunk: $chunk');

        // 根据设备返回数据的结束标识判断接收完成(示例为03d结尾)
        if (chunk.endsWith('03d')) {
          if (!completer.isCompleted) {
            completer.complete(answerBuffer.toString());
            // 完成后立即取消监听并销毁socket,阻断后续回调
            subscription?.cancel();
            socket?.destroy();
          }
        }
      },
      onDone: () {
        if (!completer.isCompleted) {
          completer.complete(answerBuffer.isEmpty ? 'Connection closed' : answerBuffer.toString());
        }
        socket?.destroy();
      },
      onError: (e) {
        if (!completer.isCompleted) {
          completer.completeError(e);
        }
        socket?.destroy();
      },
    );

    // 发送指令(移除不必要的延迟,除非设备明确要求)
    final command = 'Value:02d11d61d03d*';
    socket.add(ascii.encode(command));
    await socket.flush();

    // 等待结果或触发超时
    final response = await completer.future.timeout(
      const Duration(seconds: 5),
      onTimeout: () {
        subscription?.cancel();
        socket?.destroy();
        return 'Timeout';
      },
    );

    return response;
  } catch (e) {
    // 异常分支统一清理资源
    subscription?.cancel();
    socket?.destroy();
    return 'Error: ${e.toString()}';
  }
}
关键修复点
  • 杜绝重复完成Completer:每次调用completer.complete前检查isCompleted状态,完成后立即取消socket监听、销毁连接,阻断后续回调触发
  • 处理TCP分块数据:用StringBuffer拼接所有收到的数据包,避免单次数据覆盖导致内容不完整
  • 明确接收结束条件:根据设备返回数据的特征(如示例中的03d结尾)判断接收完成,而非收到第一块数据就结束
  • 全分支资源清理:在异常、超时、正常完成的所有分支中,都执行取消监听、销毁socket操作,避免资源泄漏
  • 移除冗余延迟:删除不必要的await Future.delayed,避免超时逻辑提前触发引发冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:15:03