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

Flutter RawDatagramSocket报Too many open files错误求助

错误原因与解决方案

错误原因

报错Too many open files (errno = 24)本质是进程打开的文件/网络套接字数量超过系统限制,结合代码分析核心问题有两点:

  1. Socket资源泄漏:_BCState作为StatefulWidget的状态类,当页面重建(如路由切换、父组件刷新)时,旧实例会被销毁,但代码未在dispose阶段调用_udpSender.close()释放UDP套接字,导致大量未关闭的Socket持续占用资源,最终触发系统限制。
  2. 递归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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:10:31