socketpair概述

socketpair是Linux系统中用于创建一对相互连接的Unix域套接字的系统调用。这对套接字类似于全双工管道(pipe),但提供了更灵活的双向通信能力,常用于进程间通信(IPC)。与pipe不同,socketpair创建的套接字对无需区分读写端,两端均可自由读写。

核心特性

  • 双向通信:两个套接字均可作为读写端点,支持全双工通信。
  • Unix域套接字:数据仅在内核中传输,不经过网络协议栈,效率更高。
  • 继承性:通过fork调用,子进程可继承父进程的套接字对。

函数原型

#include <sys/types.h>
#include <sys/socket.h>

int socketpair(int domain, int type, int protocol, int sv[2]);
  • domain:通常为AF_UNIX(Unix域)或AF_LOCAL
  • type:可选SOCK_STREAM(流式套接字)或SOCK_DGRAM(数据报套接字)。
  • protocol:通常为0,表示默认协议。
  • sv[2]:用于存储创建的两个套接字描述符的数组。

典型应用场景

  1. 父子进程通信:父进程创建套接字对后调用fork,子进程继承套接字实现通信。
  2. 线程间通信:同一进程内的线程通过共享套接字对传递数据。
  3. 替代管道:当需要双向通信时,socketpair比pipe更灵活。

代码示例:父子进程通信

以下示例展示如何使用socketpair在父子进程间传递数据:

#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main() {
    int sv[2];
    char buf[128];

    // 创建套接字对
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
        perror("socketpair");
        return 1;
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    }

    if (pid == 0) { // 子进程
        close(sv[0]); // 关闭不需要的端点
        const char *msg = "Hello from child";
        write(sv[1], msg, strlen(msg) + 1);
        close(sv[1]);
    } else { // 父进程
        close(sv[1]); // 关闭不需要的端点
        read(sv[0], buf, sizeof(buf));
        printf("Parent received: %s\n", buf);
        close(sv[0]);
    }
    return 0;
}

输出结果

Parent received: Hello from child

socketpair与pipe的对比

| 特性 | socketpair | pipe | |---------------|--------------------------|--------------------------| | 通信方向 | 全双工 | 半双工 | | 描述符类型 | 套接字 | 文件描述符 | | 灵活性 | 支持流式/数据报 | 仅字节流 | | 使用场景 | 进程/线程间双向通信 | 单向通信 |


高级用法:多线程通信

以下示例展示线程间通过socketpair传递结构化数据:

#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>

typedef struct {
    int id;
    char name[32];
} Message;

void *thread_func(void *arg) {
    int sock = *(int *)arg;
    Message msg = { .id = 1, .name = "Thread" };
    write(sock, &msg, sizeof(msg));
    return NULL;
}

int main() {
    int sv[2];
    socketpair(AF_UNIX, SOCK_STREAM, 0, sv);

    pthread_t tid;
    pthread_create(&tid, NULL, thread_func, &sv[1]);

    Message received;
    read(sv[0], &received, sizeof(received));
    printf("Received: id=%d, name=%s\n", received.id, received.name);

    close(sv[0]);
    close(sv[1]);
    return 0;
}

输出结果

Received: id=1, name=Thread

常见问题与调试

  1. EBADF错误:检查套接字描述符是否已关闭或无效。
  2. EPROTONOSUPPORT:确保协议类型与域匹配(如AF_UNIX搭配SOCK_STREAM)。
  3. 资源泄漏:务必在通信完成后关闭所有描述符。

性能优化建议

  • 缓冲区设置:通过setsockopt调整发送/接收缓冲区大小以适应高频数据传输。
  • 非阻塞模式:使用fcntl设置O_NONBLOCK标志避免I/O阻塞。
  • 信号处理:对SIGPIPE信号进行处理,防止写入已关闭的套接字导致进程终止。

通过深入理解socketpair的机制和实际应用场景,可以高效地实现Linux环境下的进程或线程间通信。

fcng5sjpybk8.feishu.cn/wiki/R1HBw7xvaiSmcTkVnxUchNuEncc?from=from_copylink
fcng5sjpybk8.feishu.cn/wiki/H95IwtW9QiCvt5kJfxycFxhHnnd?from=from_copylink
fcng5sjpybk8.feishu.cn/wiki/DDGcwMaN6ihakjk1YXkcvfk6ngd?from=from_copylink
fcng5sjpybk8.feishu.cn/wiki/MUFQwpO61iMgjAkElSQc9yRmnUX?from=from_copylink
fcng5sjpybk8.feishu.cn/wiki/A3zxwMFMyi16w9kCOXfcPOw3n5c?from=from_copylink

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐