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

Dart WebSocket 持续推送场景下指令接收与多客户端连接问题求解

问题根因

1. 服务端无法接收quit指令的原因

Dart 是单线程事件循环模型,你在 WebSocket 连接回调中写了同步阻塞的while循环+同步sleep,直接占满了主线程的执行资源,事件循环完全没有空闲时间去处理webSocket.listen的消息回调,所以客户端发的quit指令永远不会被触发执行,变量q永远不会更新为quit,循环也就不会停止。

2. 仅第一个客户端能收到消息的原因

第一个客户端连接触发回调后,同步while循环直接卡死了整个服务端线程,HttpServer没有机会处理后续新的客户端连接请求,后续客户端的连接请求都会被挂住,自然无法收到推送。另外你把running、q这类连接状态变量定义在main函数全局作用域,所有连接共享变量,即便解决了阻塞问题,多个客户端的状态也会互相覆盖干扰。

修正方案

把同步循环替换为异步周期性定时器,同时把每个连接的状态变量放到连接回调内部,每个连接独立管理自己的运行状态,不共享全局变量:

修正后的服务端代码

import 'dart:io';
import 'dart:async';

main() async {
  final port = 8080;
  final webSocketTransformer = WebSocketTransformer();
  
  HttpServer server = await HttpServer.bind(InternetAddress.anyIPv6, port);
  server.transform(webSocketTransformer).listen((WebSocket webSocket) {
    print('WebSocket opened.');
    // 每个连接独立的状态变量,不共享全局
    bool running = true;
    Timer? pushTimer;

    webSocket.listen((msg) {
      print('收到指令:$msg');
      if (msg == 'quit') {
        running = false;
        pushTimer?.cancel();
        webSocket.close();
      } else if (msg == 'start' && pushTimer == null) {
        // 启动异步周期性推送,不会阻塞事件循环
        pushTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
          if (running) {
            webSocket.add(DateTime.now().toString());
          } else {
            timer.cancel();
          }
        });
      }
    }, onError: (err) {
      running = false;
      pushTimer?.cancel();
      print(err);
    }, onDone: () {
      running = false;
      pushTimer?.cancel();
      print('WebSocket closed.');
    });
  });
  print('Listening on port $port..');
}

可选客户端优化

客户端的sleep也是同步阻塞调用,建议替换为异步等待避免卡住事件循环:

import 'dart:io';
import 'dart:async';
import 'package:web_socket_channel/io.dart';

void main(List<String> arguments) async {
  final url = 'ws://localhost:8080';
  final channel = IOWebSocketChannel.connect(url);

  channel.sink.add('start');
  channel.stream.listen((msg) {
    print(msg);
  });

  // 替换同步sleep为异步等待
  await Future.delayed(const Duration(seconds: 30));
  channel.sink.add('quit');
  await channel.sink.close();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:24:03