Flutter RawDatagramSocket报Too many open files错误求助
错误原因与解决方案
错误原因
报错Too many open files (errno = 24)本质是进程打开的文件/网络套接字数量超过系统限制,结合代码分析核心问题有两点:
- Socket资源泄漏:
_BCState作为StatefulWidget的状态类,当页面重建(如路由切换、父组件刷新)时,旧实例会被销毁,但代码未在dispose阶段调用_udpSender.close()释放UDP套接字,导致大量未关闭的Socket持续占用资源,最终触发系统限制。 - 递归Timer的任务堆积风险:当前用递归
Timer实现定时发送,若某次发送操作(如加密、网络传输)耗时超过200ms,会导致多个发送任务并发执行,进一步加剧资源占用。
解决方案
1. 销毁State时主动释放Socket资源
在_BCState中重写dispose方法,确保状态销毁时关闭UDP套接字:
@override void dispose() { _udpSender.close(); WidgetsBinding.instance.removeObserver(this); super.dispose(); }
2. 改用PeriodicTimer替代递归Timer
递归Timer易引发任务堆积,改用Timer.periodic可更可控地管理定时任务,状态切换时能及时终止任务:
Timer? _sendTimer; // 启动定时发送逻辑 void startSending() { if (_sendTimer != null) return; // 避免重复启动 _sendTimer = Timer.periodic(const Duration(milliseconds: 200), (timer) { if (!_isActive) { timer.cancel(); _sendTimer = null; return; } _udpSender.sendRelaisAndEngineCommandList( relaisCommand: _relaisCommandDirectionHandler(), engineCommand: _getEngineCommandList() ); }); } @override void dispose() { _sendTimer?.cancel(); // 取消定时任务 _udpSender.close(); WidgetsBinding.instance.removeObserver(this); super.dispose(); }
后续在需要启动发送的场景(如页面初始化、功能触发)调用startSending()即可。
3. 确认Socket复用逻辑有效性
当前UDPSender的实现是正确的:仅在构造函数中绑定一次Socket,后续所有发送操作复用该套接字,无需修改这部分代码。只需确保UDPSender实例不会被频繁创建(不要在每次发送时新建实例)。
4. 临时调整系统资源限制(可选)
若代码修复后仍出现问题,可临时提高系统文件句柄限制(以Linux为例):
- 临时生效:执行
ulimit -n 4096(当前会话有效) - 永久生效:修改
/etc/security/limits.conf,添加* soft nofile 4096和* hard nofile 8192后重启系统
此为应急方案,优先解决代码层面的资源泄漏问题。
内容的提问来源于stack exchange,提问作者Michael Marolt
相关产品推荐
相关产品推荐

