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); }
问题根源
s.timeout(Duration(seconds:5))仅返回一个带超时逻辑的新Stream,但你仍在监听原Socket的流,超时逻辑完全没触发。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
相关产品推荐
相关产品推荐

