
出於安全合規,核心數據庫常部署在隔離網段,僅允許特定應用服務器直連。其它業務系統需通過遠程調用服務代理訪問數據庫:客戶端發送 SQL/Shell 命令 → 服務端驗證權限 → 執行命令 → 返回結果。本文實現一個通用Shell 命令遠程執行服務,展示分布式遠程調用核心模型。
fork() 多進程模型(簡單穩健)或 epoll 事件驅動(高併發)。system():簡單但無法交互獲取輸出,需重定向臨時文件fork()+exec():控制力最強,但需自管管道/信號popen("cmd", "r"):首選,內部建立管道,FILE* 流式讀取標準輸出,自動回收子進程FILE *fp = popen(cmd, "r"); // 建立管道、啟動命令
char line[8192];
while (fgets(line, sizeof(line), fp) != NULL) {
send(sock, line, strlen(line), 0); // 逐行發送給客戶端
}
pclose(fp); // 關閉管道、回收子進程、獲取退出碼
優勢:流式處理、無臨時文件、自動同步(讀完即命令結束)、代碼極簡。
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PORT 8888
#define BACKLOG 10
void handle_client(int client_sock) {
char cmd[1024];
int n = recv(client_sock, cmd, sizeof(cmd)-1, 0);
if (n <= 0) return;
cmd[n] = '\0';
// 簡單認證(生產環境需 TLS+強認證)
if (strncmp(cmd, "AUTH:secret:", 12) != 0) {
send(client_sock, "401 Unauthorized\n", 17, 0);
return;
}
char *real_cmd = cmd + 12;
FILE *fp = popen(real_cmd, "r");
if (!fp) {
send(client_sock, "500 Execute Failed\n", 19, 0);
return;
}
char buf[4096];
while (fgets(buf, sizeof(buf), fp)) {
send(client_sock, buf, strlen(buf), 0);
}
pclose(fp);
close(client_sock);
_exit(0); // 子進程退出
}
int main() {
signal(SIGCHLD, SIG_IGN); // 避免僵死進程
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
bind(server_sock, (struct sockaddr*)&addr, sizeof(addr));
listen(server_sock, BACKLOG);
printf("Remote Exec Server listening on %d...\n", PORT);
while (1) {
int client_sock = accept(server_sock, NULL, NULL);
if (client_sock < 0) continue;
if (fork() == 0) {
close(server_sock);
handle_client(client_sock);
}
close(client_sock); // 父進程關閉客戶端描述符
}
return 0;
}
# 編譯服務端
gcc -o remote_exec_server server.c
# 運行服務端
./remote_exec_server &
# 客戶端發送命令(nc 模擬)
echo "AUTH:secret:df -h /data" | nc 127.0.0.1 8888
echo "AUTH:secret:ps aux | grep java" | nc 127.0.0.1 8888
| 風險 | 對策 |
|---|---|
| 命令注入 | 白名單模式:只允許預定義命令模板,參數化傳遞;禁用 Shell 元字符 |
| 明文傳輸 | 強制 TLS 1.2+,雙向證書認證 |
| 權限過大 | 服務端以最小權限用戶運行;命令通過 sudo 精確提權 |
| 拒絕服務 | 連接數限制、命令執行超時、輸出大小限制、速率限制 |
| 審計缺失 | 全量記錄:請求源 IP、用戶、命令、耗時、退出碼、輸出摘要 |
階段1:單機多進程(本文實現) → 簡單、穩定、低併發
階段2:Reactor 事件驅動+線程池 → C10K 併發、資源效率高
階段3:RPC 框架化 封裝 → 定義 IDL、自動生成存根、服務治理
階段4:Service Mesh 化 → Sidecar 代理、流量治理、可觀測性
遠程調用模型是分布式系統基石。本文通過 popen+多進程 Socket 實現了最小可用原型,展示了命令執行、流式輸出、並發隔離、安全邊界四大核心要素。實戰中務必在安全、可觀測、治理三維度持續演進,切勿將裸露的 Shell 執行接口暴露於非受信網絡。