首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

分布式遠程調用模型實戰:基於 Socket 與 Popend 的命令執行服務

     編輯:關於C語言

遠程調用模型

應用場景與架構定位

出於安全合規,核心數據庫常部署在隔離網段,僅允許特定應用服務器直連。其它業務系統需通過遠程調用服務代理訪問數據庫:客戶端發送 SQL/Shell 命令 → 服務端驗證權限 → 執行命令 → 返回結果。本文實現一個通用Shell 命令遠程執行服務,展示分布式遠程調用核心模型。

系統分析:三大核心技術難點

  1. 並發請求處理:多客戶端同時連接,採用 fork() 多進程模型(簡單穩健)或 epoll 事件驅動(高併發)。
  2. 命令執行方式選擇:
    • system():簡單但無法交互獲取輸出,需重定向臨時文件
    • fork()+exec():控制力最強,但需自管管道/信號
    • popen("cmd", "r"):首選,內部建立管道,FILE* 流式讀取標準輸出,自動回收子進程
  3. 輸出結果獲取與傳輸:命令可能產生大量輸出,需分塊讀取、分塊發送,防止緩衝區溢出或死鎖。

Popen 交互式讀取核心代碼

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 執行接口暴露於非受信網絡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved