当前位置: 首页 > news >正文

OTA升级失败,端口占用bind: Address already in use

目前程序的OTA逻辑是判断MD5SUM,如果不匹配,则下载新程序,杀掉旧程序启动新程序。

今天突然发现ota升级不管用了,查看后台进程发现老进程没有完全退出。导致端口被占用。

源代码:


// 重命名运行的程序, 下载的新程序名字覆盖
static int download_exec(const string& download_address, string cloud_md5)
{rename(PROGRAM_NAME, PROGRAM_NAME_HIS);string wget_cmd = "wget " + download_address + " -O " + PROGRAM_NAME +" -q -o wgetlog";FILE *f = popen(wget_cmd.c_str(), "r");char res[512];if(fread(res, 1, sizeof(res), f) < 0){hloge("Download Failed");pclose(f);return -1;}                                                         // 阻塞主程序,等待下载完成string download_md5 = local_md5_get();hlogi("download md5:%s", download_md5);//cout<<"download_md5"<<download_md5<<endl;hlogi("cloud md5:%d", cloud_md5);//cout<<"cloud_md5"<<cloud_md5<<endl;if(cloud_md5.compare(download_md5) != 0){                   // 下载失败/MD5校验不匹配rename(PROGRAM_NAME_HIS, PROGRAM_NAME);pclose(f);return -1;}hlogi("file download success");// fstream tmpfile("./.update", ios::out | ios::app);      // 下载成功时,创建临时文件// tmpfile.close();hlogi("Ready to execute new program");string exe_path = "./" + (string)PROGRAM_NAME;update_chmod(exe_path);pid_t pid;pid = fork();   //这里不能正常退出sleep(10);if(pid < 0){hloge("failed to fork child porcess\n");}else if(pid > 0){hlogi("Old process end");_exit(0);}else{if(execl(exe_path.c_str(), "Laserbird", NULL) == -1){         // 执行下载的程序hloge("FATAL ERROR: Failed to execute new version serivce");return -1;}}return 0;
}

研究发现fork 后父进程直接 exit 可能导致后台僵尸进程

解决方案很简单,把exit(0)改成

        _exit(0)
区别:

exit() 会执行标准库清理(比如 flush 输出缓冲区、调用 atexit 注册的函数等)。

_exit() 不做清理,直接从内核退出进程,更适合在 fork() 后的父进程中使用,避免留下僵尸进程。

exit()_exit() 的差异

函数来自会清理 stdio 缓冲区会执行 atexit 函数直接退出到内核
exit()C 标准库✅ 是✅ 是❌ 否
_exit()系统调用❌ 否❌ 否✅ 是
// 父进程调用 exit()
pid_t pid = fork();
if (pid > 0) {exit(0);  // 可能留下僵尸
}// 父进程调用 _exit()
pid_t pid = fork();
if (pid > 0) {_exit(0);  // 不会留下僵尸
}


这样正常OTA就没问题。

 

 

http://www.dtcms.com/a/291355.html

相关文章:

  • 酵母杂交技术解析
  • 微服务项目文档
  • ABeam News | 中野洋辅董事长专访:扎根上海二十载,做中日企业的卓越桥梁
  • 【人工智能99问】什么是教师强制?(16/99)
  • Spring Cache 扩展:Redis 批量操作优化方案与 BatchCache 自定义实现
  • 2130、链表最大孪生和
  • rsync报错解决
  • Shopify 知识点
  • 草木知音的认知进化:Deepoc具身智能如何让除草机读懂花园的呼吸
  • 设备监控之数据处理(1)-概述
  • MQ 核心知识点笔记
  • Android开发中卡顿治理方案
  • 用基础模型构建应用(第十章)AI Engineering: Building Applications with Foundation Models学习笔记
  • 如何用纯 HTML 文件实现 Vue.js 应用,并通过 CDN 引入 Element UI
  • 【PHP 流程控制完全指南】
  • 多端适配灾难现场:可视化界面在PC/平板/大屏端的响应式布局实战
  • .NET依赖注入IOC你了解吗?
  • 开发避坑短篇(3):解决@vitejs plugin-vue@5.0.5对Vite^5.0.0的依赖冲突
  • 万界星空科技锂电池MES解决方案
  • Shell判断结构
  • voice模块
  • 【图论】CF——B. Chamber of Secrets (0-1BFS)
  • 标准文件I/O补充知识
  • paddleocr安装,数据集制作,训练自己的模型,调用训练好的模型
  • 20250721-day19
  • 【PTA数据结构 | C语言版】双连通分量
  • C# 实现:动态规划解决 0/1 背包问题
  • nextjs编程式跳转
  • 《小白学习产品经理》第七章:方法论之波特五力模型
  • springcloud -- 微服务02