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

深入理解 socketpair:雙向通訊機制與進程間應用實戰

     編輯:關於C語言

前言

socketpair 是 UNIX 系統編程中一個強大且常被忽視的系統呼叫,它能建立一對已連線的無名套接字,支援全雙工通訊。本文將從原理、單進程驗證、父子進程通訊、與 pipe 差異比較,到核心實作機制進行深度解析,並附上完整可編譯的程式碼範例。

一、核心概念

  • 域限制:僅能在 AF_UNIX (或 AF_LOCAL) 域使用。
  • 雙工特性:回傳的兩個檔案描述符 s[0]、s[1] 均可讀可寫,互為對端。
  • 資料流向:寫入 s[0] 可從 s[1] 讀取,反之亦然;同一描述符寫入後不可自我讀取。
  • 阻塞行為:若無資料可讀,read 會阻塞,即使同一端已寫入資料也無法解除阻塞。

二、單進程驗證程式

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <error.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdlib.h>

#define BUF_SIZE 30

int main() {
    int s[2];
    int w, r;
    char *string = "This is a test string";
    char *buf = (char*)calloc(1, BUF_SIZE);

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
        printf("create unnamed socket pair failed: %s\n", strerror(errno));
        exit(-1);
    }

    // 寫入 s[0],從 s[1] 讀取
    if ((w = write(s[0], string, strlen(string))) == -1) {
        printf("Write socket error: %s\n", strerror(errno));
        exit(-1);
    }
    if ((r = read(s[1], buf, BUF_SIZE)) == -1) {
        printf("Read from socket error: %s\n", strerror(errno));
        exit(-1);
    }
    printf("Read string in same process: %s\n", buf);

    // 驗證同一端不可讀取自己寫入的資料
    if ((r = read(s[0], buf, BUF_SIZE)) == -1) {
        printf("Read from socket s0 error: %s\n", strerror(errno));
        exit(-1);
    }
    printf("Read from s0: %s\n", buf); // 應阻塞或讀不到剛寫入的資料

    printf("Test successed\n");
    return 0;
}

三、父子進程雙工通訊

透過 fork() 建立子進程,父進程關閉 s[1],子進程關閉 s[0],即可實現雙向通訊:

// 關鍵片段
pid_t pid;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) { /* 錯誤處理 */ }

if ((pid = fork()) > 0) {          // 父進程
    close(s[1]);
    write(s[0], string, strlen(string));
} else if (pid == 0) {             // 子進程
    close(s[0]);
    read(s[1], buf, BUF_SIZE);
    printf("Child read: %s\n", buf);
}
// 父子皆可互為讀寫端,實現全雙工

四、socketpair vs pipe 差異比較

特性pipesocketpair
通訊模式半雙工(單向)全雙工(雙向)
描述符角色固定讀端/寫端對等,皆可讀寫
適用場景單向資料流(如 Shell 管線)雙向互動(如父子進程協作、狀態同步)

五、進階議題:多讀端競爭與 EOF 語意

若父子進程皆不關閉任一描述符,兩者共享同一檔案表項,會對同一資料流產生競爭讀取:

  • 先讀到資料的進程取得內容,另一進程讀到空資料或阻塞。
  • 若寫端引用計數歸零(所有持有寫端的進程皆關閉或結束),剩餘讀端會讀到 EOF(回傳 0)。
  • 若寫端仍有引用(如父進程未關閉),子進程讀完結束後,父進程 read 會持續阻塞等待新資料。

此行為可用「寫端引用計數」與「檔案表項共享」機制完整解釋。

六、核心層面實作概述

  1. socketpair 在核心中建立兩個 struct socket 物件,屬於虛擬網路檔案系統(非實體檔案系統)。
  2. 兩者的 peer 指標互指,形成邏輯迴路,核心內部以環狀緩衝區實現資料傳遞。
  3. 應用層呼叫 read/write 實際轉呼叫 socket 家族的 sock_read/sock_write。
  4. fork 時子進程繼承父進程的檔案描述符表,指向相同的 struct file 與 socket 物件,因此共享偏移量、緩衝區與引用計數。

七、總結

socketpair 是進程間通訊(IPC)的利器,特別適合需要雙向、低延遲、無需命名的通訊場景。理解其引用計數、EOF 語意與核心實作,有助於避免常見的阻塞、資料搶讀等陷阱。建議在父子進程協作、事件迴路內部通知等場景優先考慮使用。

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