Windows下UDP监听异常处理:如何忽略OS错误持续运行
Windows下Dart UDP监听时忽略无效端口发送异常的解决方案
问题现象
在Windows 10系统中使用Dart的RawDatagramSocket绑定并监听UDP端口时,向无服务运行的端口发送数据会引发异常,且会导致监听终止,无法继续接收后续数据:
- 当先向有监听的端口(如9999)发送数据,再向无服务端口(如12345)发送时,监听会静默停止,无错误提示:
import 'dart:io'; import 'dart:convert'; void main() async { RawDatagramSocket.bind(InternetAddress.anyIPv4, 9999) .then((RawDatagramSocket socket) { socket.broadcastEnabled = true; socket.listen( (RawSocketEvent event) { if (event == RawSocketEvent.read) { Datagram? datagram = socket.receive(); if (datagram != null) { String message = utf8.decode(datagram.data); print( 'Received: $message from ${datagram.address.address}:${datagram.port}'); } } }, onError: (e, s) { print('Error: $e'); }, cancelOnError: false, onDone: () { print('Done'); }); socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 9999); socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 9999); socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 12345); socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 9999); }); }
执行输出:
Received: hello from 127.0.0.1:9999 Received: hello from 127.0.0.1:9999
最后一次向9999发送的数据无法被接收,监听已停止。
- 若直接向无服务端口发送,会直接抛出异常导致程序终止:
import 'dart:io'; import 'dart:convert'; void main() async { RawDatagramSocket.bind(InternetAddress.anyIPv4, 9999) .then((RawDatagramSocket socket) { socket.broadcastEnabled = true; socket.listen( (RawSocketEvent event) { if (event == RawSocketEvent.read) { Datagram? datagram = socket.receive(); if (datagram != null) { String message = utf8.decode(datagram.data); print( 'Received: $message from ${datagram.address.address}:${datagram.port}'); } } }, onError: (e, s) { print('Error: $e'); }, cancelOnError: false, onDone: () { print('Done'); }); // socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 9999); // socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 9999); socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 12345); socket.send(utf8.encode("hello"), InternetAddress('127.0.0.1'), 9999); }); }
执行输出:
Error: SocketException: No service is operating at the destination network endpoint on the remote system (OS Error: No service is operating at the destination network endpoint on the remote system。 , errno = 1234), address = 0.0.0.0, port = 9999
问题原因
这是Windows平台特有的UDP错误反馈机制导致的:当向无监听的UDP端口发送数据时,目标系统会返回ICMP「端口不可达」错误,该错误会关联到发送数据的RawDatagramSocket。如果这个socket同时是监听socket,错误会导致监听逻辑终止,甚至直接抛出异常终止程序。
解决方案
核心思路是分离监听与发送的socket:主socket仅负责监听UDP数据,发送操作使用临时创建的socket完成。这样即使发送到无效端口引发异常,也只会影响临时socket,不会中断主监听逻辑。
优化后的实现代码
import 'dart:io'; import 'dart:convert'; // 发送UDP数据的工具方法,使用临时socket Future<void> sendUdpMessage(String message, String ip, int port) async { try { // 创建临时socket,绑定任意可用端口(Windows允许多个UDP socket绑定同端口) final tempSocket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); tempSocket.send(utf8.encode(message), InternetAddress(ip), port); tempSocket.close(); } catch (e) { // 捕获并忽略发送异常,不影响主监听 print('发送失败:$e'); } } void main() async { // 主socket仅负责监听 final mainSocket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 9999); mainSocket.broadcastEnabled = true; mainSocket.listen( (RawSocketEvent event) { if (event == RawSocketEvent.read) { final datagram = mainSocket.receive(); if (datagram != null) { final message = utf8.decode(datagram.data); print('Received: $message from ${datagram.address.address}:${datagram.port}'); } } }, onError: (e, s) { print('监听错误:$e'); }, cancelOnError: false, onDone: () { print('监听结束'); } ); // 执行发送操作,使用临时socket await sendUdpMessage("hello", '127.0.0.1', 9999); await sendUdpMessage("hello", '127.0.0.1', 9999); await sendUdpMessage("hello", '127.0.0.1', 12345); // 向无效端口发送,仅临时socket受影响 await sendUdpMessage("hello", '127.0.0.1', 9999); // 主监听仍能接收该数据 }
代码说明
- 分离职责:主
mainSocket只处理监听逻辑,不参与发送操作,避免发送错误影响监听。 - 临时发送socket:
sendUdpMessage方法中创建临时socket完成发送,发送后立即关闭。即使发送到无效端口抛出异常,也会被try-catch捕获,不会影响主程序。 - 异常捕获:在发送方法内捕获异常,可以选择打印日志或静默忽略,不中断主监听流程。
效果验证
执行上述代码后,即使向无服务端口12345发送数据,主监听仍能正常接收后续发送到9999的数据,输出如下:
Received: hello from 127.0.0.1:9999 Received: hello from 127.0.0.1:9999 发送失败:SocketException: No service is operating at the destination network endpoint on the remote system (OS Error: No service is operating at the destination network endpoint on the remote system。, errno = 1234), address = 0.0.0.0, port = 0 Received: hello from 127.0.0.1:9999
内容的提问来源于stack exchange,提问作者song wu
相关产品推荐
相关产品推荐

