通過管道(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. 處理結果。
關鍵在于確保數據完整傳輸、妥善處理錯誤,并根據實際需求擴展超時、雙向通信等功能。