通过管道(popen
)启动 SDIWAN_WEB
进程并写入 JSON 数据的过程可以分为以下步骤,结合代码示例和关键注意事项进行说明:
1. 核心代码示例
#include <stdio.h>
#include <json-c/json.h>int main() {// 1. 创建 JSON 对象json_object *root = json_object_new_object();json_object_object_add(root, "action", json_object_new_string("create_wan"));json_object_object_add(root, "param", json_object_new_string("eth0"));// 2. 将 JSON 对象转换为字符串const char *json_str = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY);// 3. 通过 popen 启动 SDIWAN_WEB 进程(写入模式)FILE *fp = popen("SDIWAN_WEB", "w");if (!fp) {perror("popen failed");return -1;}// 4. 写入 JSON 数据到管道size_t json_len = strlen(json_str);size_t written = fwrite(json_str, 1, json_len, fp);if (written != json_len) {perror("fwrite failed");pclose(fp);return -1;}// 5. 关闭管道并检查子进程退出状态int status = pclose(fp);if (status == -1) {perror("pclose failed");return -1;} else if (WIFEXITED(status)) {int exit_code = WEXITSTATUS(status);printf("SDIWAN_WEB exited with code: %d\n", exit_code);}// 6. 释放 JSON 对象json_object_put(root);return 0;
}
2. 关键步骤解析
(1) 创建 JSON 对象
- 作用:构造需要传递给
SDIWAN_WEB
的配置数据。 - 代码:
json_object *root = json_object_new_object(); json_object_object_add(root, "action", json_object_new_string("create_wan")); json_object_object_add(root, "param", json_object_new_string("eth0"));
- 说明:
- 使用
json-c
库动态构建 JSON 对象。 - 示例中添加了
action
和param
字段,实际需根据SDIWAN_WEB
的接口定义填充数据。
- 使用
(2) 转换为字符串
- 作用:将 JSON 对象序列化为字符串,便于通过管道传输。
- 代码:
const char *json_str = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY);
- 说明:
JSON_C_TO_STRING_PRETTY
使输出格式化(可读性更好),若需紧凑格式可替换为JSON_C_TO_STRING_PLAIN
。
(3) 启动子进程
- 作用:通过
popen
启动SDIWAN_WEB
进程,并建立写入管道。 - 代码:
FILE *fp = popen("SDIWAN_WEB", "w");
- 说明:
"w"
表示以写入模式打开管道,子进程的标准输入(stdin
)连接到管道。SDIWAN_WEB
需为可执行文件的完整路径(如/usr/bin/SDIWAN_WEB
)。
(4) 写入数据
- 作用:将 JSON 字符串写入管道,由子进程读取。
- 代码:
size_t written = fwrite(json_str, 1, json_len, fp);
- 说明:
- 必须检查
fwrite
返回值,确保完整写入数据。 - 若写入失败,需调用
pclose
关闭管道并释放资源。
- 必须检查
(5) 关闭管道并检查状态
- 作用:关闭管道并获取子进程退出状态。
- 代码:
int status = pclose(fp); if (WIFEXITED(status)) {int exit_code = WEXITSTATUS(status);printf("Exit code: %d\n", exit_code); }
- 说明:
pclose
会等待子进程结束并返回其退出状态。WIFEXITED(status)
判断子进程是否正常退出,WEXITSTATUS
获取退出码。
3. 注意事项
(1) 错误处理
- 关键点:
- 检查
popen
是否返回NULL
(如可执行文件不存在或权限不足)。 - 检查
fwrite
是否完整写入数据。 - 检查
pclose
是否成功,并处理子进程异常退出(如被信号终止)。
- 检查
(2) 数据完整性
- 关键点:
- 确保 JSON 字符串以
\0
结尾,或明确指定长度(如示例中的json_len
)。 - 若
SDIWAN_WEB
需要严格的数据格式(如结尾换行符),需在写入时添加。
- 确保 JSON 字符串以
(3) 安全性
- 关键点:
- 避免将用户输入直接拼接到命令中(
popen
的参数是固定字符串,无命令注入风险)。 - 确保 JSON 数据来源可信,防止恶意数据导致子进程异常。
- 避免将用户输入直接拼接到命令中(
(4) 性能优化
- 关键点:
- 对于大数据量,可分块写入(如循环调用
fwrite
)。 - 使用
fflush(fp)
强制刷新缓冲区,确保数据及时到达子进程。
- 对于大数据量,可分块写入(如循环调用
4. 扩展场景
(1) 双向通信
- 若需从
SDIWAN_WEB
读取响应,可使用popen
的读取模式("r"
),但需注意:- 写入和读取需分两个独立管道。
- 可能需要多线程或
select
实现并发读写。
(2) 超时控制
- 通过
alarm
或select
设置超时,避免子进程卡死:#include <unistd.h> #include <sys/select.h>// 设置 5 秒超时 alarm(5); int status = pclose(fp); alarm(0);
5. 总结
通过 popen
启动 SDIWAN_WEB
并写入 JSON 数据的流程如下:
- 构造 JSON → 2. 启动进程 → 3. 写入数据 → 4. 关闭管道 → 5. 处理结果。
关键在于确保数据完整传输、妥善处理错误,并根据实际需求扩展超时、双向通信等功能。