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

Flutter中WebSocket流完成时如何正确获取sendMessage返回值

问题核心原因

你当前代码返回null的本质是stream.listen()属于非阻塞注册监听的操作:调用后仅会绑定消息回调,不会等待回调执行,代码会直接向下执行到return语句,此时服务端响应还未返回,存储结果的aux变量还未被赋值,因此返回null。


sendMessage() 方法的正确实现

不要使用listen()做单次请求响应式的WebSocket通信,改用流的等待类方法(如firstWhere、await for)阻塞等待目标响应,拿到结果后再关闭连接、返回值,同时补全连接失败、通信异常的边界处理。
修正后的完整代码如下:

Future<String> sendMessage(dynamic msg, String ip, String port) async {
  WebSocketChannel? channel;
  try {
    // 建立WebSocket连接
    channel = WebSocketChannel.connect(Uri.parse('ws://$ip:$port'));
    // 向服务端发送消息
    channel.sink.add(msg);

    // 等待流中返回第一个符合要求的业务响应
    final targetResponse = await channel.stream.firstWhere(
      (event) {
        // 过滤空消息、"Connected"这类握手提示消息,只保留目标业务响应
        final respStr = event?.toString() ?? '';
        return respStr.isNotEmpty && respStr != 'Connected';
      },
    );

    // 拿到响应后主动关闭连接
    await channel.sink.close();
    return targetResponse.toString();
  } catch (e) {
    print("WebSocket通信异常: ${e.toString()}");
    // 异常场景下强制关闭连接释放资源
    await channel?.sink.close();
    // 可根据业务需求返回错误标识,或直接抛出异常由上层处理
    rethrow;
  }
}

sendMessage() 的正确调用方式

你原本的await调用写法逻辑是正确的,只要sendMessage内部正确实现异步等待,外层的await就会自动阻塞直到通信完成拿到返回值,再执行后续逻辑。调用示例:

try {
  // await会等待整个通信流程完成后,才会把结果赋值给response
  String response = await sendMessage(jsonString, device_ip, '199');
  // 后续的响应解析、UI更新等逻辑直接写在这里即可
  print("服务端返回结果:$response");
} catch (e) {
  // 统一处理连接失败、消息发送超时、服务端报错等异常场景
  print("消息发送失败:$e");
}

原代码的其他问题说明
  • 未处理连接失败场景:如果WebSocket连接阶段抛出异常,channel会保持null状态,后续调用sink.add、stream.listen会触发空指针报错
  • 未等待连接、流操作的异步结果:整个方法内除了函数标记为async,没有任何真正等待异步任务完成的逻辑,返回时机远早于通信完成时间
  • 异常捕获不全:仅捕获了连接阶段的异常,消息发送、流监听阶段的异常完全没有处理,容易出现未捕获的崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:15:35