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
相关产品推荐
相关产品推荐

