banner
NEWS LETTER

嵌入式 Linux 系列 26:C 语言服务代码的工程实践

Scroll down

嵌入式 Linux 上的 C 服务代码,不只是能编译运行就可以。它要长期运行,要处理异常输入,要能记录日志,要能重载配置,要能在资源紧张和网络异常时保持可控。

一、错误处理要明确

不要忽略返回值:

1
2
3
4
5
int fd = open(path, O_RDONLY);
if (fd < 0) {
log_error("open %s failed: %s", path, strerror(errno));
return -1;
}

嵌入式现场问题很多都靠错误日志定位。只返回失败、不打印 errno,排查会很困难。

二、资源释放要统一

C 代码容易泄漏 fd、内存、锁。

常见写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int ret = -1;
int fd = -1;
char *buf = NULL;

fd = open(path, O_RDONLY);
if (fd < 0) {
goto out;
}

buf = malloc(1024);
if (!buf) {
goto out;
}

ret = 0;

out:
free(buf);
if (fd >= 0) {
close(fd);
}
return ret;

统一出口比到处 return 更容易维护。

三、配置加载

配置加载要做:

  • 文件是否存在。
  • JSON 是否合法。
  • 字段是否缺失。
  • 值是否越界。
  • 版本是否需要迁移。
  • 默认值是否明确。

不要让坏配置直接导致进程崩溃。

四、日志接口

至少区分级别:

1
2
3
4
ERROR
WARN
INFO
DEBUG

日志要包含模块:

1
2
INFO mqtt connected host=...
ERROR config parse failed path=... err=...

量产版本默认不要打开大量 DEBUG。

五、主循环设计

主循环要能处理:

  • 退出信号。
  • 定时任务。
  • 网络事件。
  • 配置 reload。
  • watchdog 心跳。

不要写不可退出的死循环:

1
2
3
while (1) {
do_work();
}

至少要有 sleep、事件等待或阻塞 IO。

六、信号处理

常用:

1
2
3
SIGTERM
SIGINT
SIGHUP

可以约定:

  • SIGTERM:优雅退出。
  • SIGHUP:重载配置。

信号处理函数里不要做复杂逻辑,只设置标志位。

七、验收清单

一个 C 服务至少要验证:

  • 配置缺失能启动默认值。
  • 配置损坏有错误日志。
  • 网络断开能重连。
  • SIGTERM 能退出。
  • SIGHUP 能重载配置。
  • 长时间运行内存不持续增长。
  • 日志不会刷爆分区。

C 服务代码的质量,最终体现在异常路径能不能稳住。

其他文章
目录导航 置顶
  1. 1. 一、错误处理要明确
  2. 2. 二、资源释放要统一
  3. 3. 三、配置加载
  4. 4. 四、日志接口
  5. 5. 五、主循环设计
  6. 6. 六、信号处理
  7. 7. 七、验收清单
请输入关键词进行搜索