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

Dart UDP Socket无法超时求助:如何实现5秒监听超时

Dart UDP Socket监听无法超时的问题解决

我需要创建一个UDP Socket,先广播数据,然后在5秒内监听设备响应。当前代码能正常广播和接收响应,但永远不会超时,一直处于监听状态。我以为RawDatagramSocket的timeout方法能直接设置超时,但它只返回Stream<RawSocketEvent>实例,原写法根本没生效。

原代码如下:

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

Future <void> sendData() async {
  List<int> buffer = utf8.encode('foobar');
  RawDatagramSocket s = await RawDatagramSocket.bind(InternetAddress('192.168.1.123'), 0);  // 我的PC的IP
  s.broadcastEnabled = true;

  // 调用`timeout`会返回`Stream<RawSocketEvent>`实例,因此我认为当前写法不会生效,但我想要实现的是监听5秒超时。
  s.timeout(Duration(seconds: 5));
  var subscription = s.listen((RawSocketEvent e) async {
    Datagram? dg = s.receive();
    if (dg != null) {
      print('Received:');
      print(utf8.decode(dg.data));
    }
  });

  s.send(buffer, InternetAddress('255.255.255.255'), 1234);
  await subscription.asFuture<void>(); // 永远无法通过此处
  s.close();
}


Future<void> main() async {
  await sendData();
  exit(0);
}

问题根源

  1. s.timeout(Duration(seconds:5))仅返回一个带超时逻辑的新Stream,但你仍在监听原Socket的流,超时逻辑完全没触发。
  2. subscription.asFuture<void>()会一直阻塞,直到Stream主动结束,但UDP Socket的流除非手动关闭,否则不会自动终止。

解决方案一:使用timeout返回的Stream监听

直接使用timeout生成的新Stream进行监听,在超时触发时关闭流,让监听流程正常结束:

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

Future<void> sendData() async {
  List<int> buffer = utf8.encode('foobar');
  RawDatagramSocket s = await RawDatagramSocket.bind(InternetAddress('192.168.1.123'), 0);
  s.broadcastEnabled = true;

  // 监听timeout返回的带超时逻辑的新Stream
  final timeoutStream = s.timeout(const Duration(seconds: 5), onTimeout: (sink) {
    print('监听超时,停止等待响应');
    sink.close(); // 关闭流触发onDone
  });

  var subscription = timeoutStream.listen((RawSocketEvent e) {
    Datagram? dg = s.receive();
    if (dg != null) {
      print('Received:');
      print(utf8.decode(dg.data));
      // 可选:收到第一个响应后主动停止监听
      // subscription.cancel();
    }
  }, onDone: () {
    // 超时或手动取消监听时关闭Socket
    s.close();
  }, onError: (error) {
    print('监听出错: $error');
    s.close();
  });

  s.send(buffer, InternetAddress('255.255.255.255'), 1234);
  await subscription.asFuture<void>();
}

Future<void> main() async {
  await sendData();
  exit(0);
}

解决方案二:用Future.any实现超时竞争

通过Future.any让监听任务和超时任务竞争,哪个先完成就执行对应的逻辑:

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

Future<void> sendData() async {
  List<int> buffer = utf8.encode('foobar');
  RawDatagramSocket s = await RawDatagramSocket.bind(InternetAddress('192.168.1.123'), 0);
  s.broadcastEnabled = true;

  final subscription = s.listen((RawSocketEvent e) {
    Datagram? dg = s.receive();
    if (dg != null) {
      print('Received:');
      print(utf8.decode(dg.data));
    }
  });

  s.send(buffer, InternetAddress('255.255.255.255'), 1234);

  // 同时等待监听结束和超时,先完成的任务会终止等待
  await Future.any([
    subscription.asFuture<void>(),
    Future.delayed(const Duration(seconds: 5)).then((_) {
      print('监听超时');
      subscription.cancel(); // 取消监听触发流程结束
    }),
  ]);

  s.close();
}

Future<void> main() async {
  await sendData();
  exit(0);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:20:33