c++中socketpair函数示例详解
作者:青草地溪水旁
socketpair()创建已连接的匿名Unix套接字对,用于高效进程间通信,无需绑定或连接,支持双向流式/数据报通信,适用于父子进程和线程,相比管道,提供全双工能力,结合了易用性与灵活性,本文给大家介绍c++中socketpair函数示例,感兴趣的朋友一起看看吧
socketpair() 是 Unix/Linux 系统中用于创建一对相互连接的匿名套接字的系统调用,专为 进程间通信 (IPC) 设计。这对套接字在创建后即处于连接状态,无需绑定地址或手动连接,特别适用于父子进程或线程间通信。
函数原型
#include <sys/types.h> #include <sys/socket.h> int socketpair(int domain, int type, int protocol, int sv[2]);
| 参数 | 说明 |
|---|---|
domain | 协议族:通常为 AF_UNIX(本地通信)或 AF_LOCAL(同义) |
type | 套接字类型:SOCK_STREAM(流式)或 SOCK_DGRAM(数据报) |
protocol | 协议:通常为 0(自动选择) |
sv[2] | 用于存储两个套接字描述符的数组(输出参数) |
| 返回值 | 成功返回 0,失败返回 -1 并设置 errno |
核心特性
- 匿名连接
- 套接字对在创建时已自动连接,无需调用
bind(),listen(),accept(),connect()。
- 套接字对在创建时已自动连接,无需调用
- 双向通信
- 两个套接字均可读写(全双工)。
- 高效 IPC
- 数据在内核中直接传递,无需经过网络协议栈。
- 无文件路径
- 与命名 Unix 套接字不同,不会在文件系统中创建节点。
使用场景
- 父子进程通信
- 父进程创建套接字对 →
fork()→ 父子进程各关闭一端 → 通过剩余套接字通信。
- 父进程创建套接字对 →
- 线程间通信
- 线程可直接通过套接字描述符交换数据。
- 替代管道 (pipe)
- 提供双向通信能力(管道是单向的)。
使用步骤
- 调用
socketpair()创建套接字对 - 根据场景关闭不需要的描述符
- 通过
read()/write()或send()/recv()通信 - 通信完成后关闭所有描述符
示例代码:父子进程通信
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int sv[2]; // 套接字对
pid_t pid;
char buf[128];
// 1. 创建流式套接字对
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
perror("socketpair");
exit(1);
}
// 2. 创建子进程
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { // 子进程
close(sv[0]); // 关闭父进程端
// 3. 向父进程发送消息
const char *msg = "Hello from child";
write(sv[1], msg, strlen(msg) + 1);
// 4. 接收父进程回复
read(sv[1], buf, sizeof(buf));
printf("Child received: %s\n", buf);
close(sv[1]); // 关闭子进程端
exit(0);
}
else { // 父进程
close(sv[1]); // 关闭子进程端
// 3. 接收子进程消息
read(sv[0], buf, sizeof(buf));
printf("Parent received: %s\n", buf);
// 4. 回复子进程
const char *reply = "Hello from parent";
write(sv[0], reply, strlen(reply) + 1);
close(sv[0]); // 关闭父进程端
wait(NULL); // 等待子进程退出
}
return 0;
}关键参数详解
1.domain协议族
AF_UNIX/AF_LOCAL
本地通信(进程间通信),唯一推荐选项(其他如AF_INET通常不支持)。
2.type套接字类型
| 类型 | 特性 |
|---|---|
SOCK_STREAM | 可靠、双向、面向连接的字节流(类似 TCP),无消息边界 |
SOCK_DGRAM | 数据报服务(类似 UDP),保留消息边界(在 AF_UNIX 中仍可靠) |
| 扩展标志 | |
SOCK_NONBLOCK | 非阻塞模式(Linux 特有,如 SOCK_STREAM | SOCK_NONBLOCK) |
SOCK_CLOEXEC | 执行 exec 时关闭描述符(避免泄漏) |
3.protocol
- 固定为
0(系统自动选择协议)。
与管道的对比
| 特性 | socketpair() | pipe() |
|---|---|---|
| 通信方向 | 双向(全双工) | 单向(半双工) |
| 数据流类型 | 流式/数据报 | 字节流 |
| 描述符数量 | 2 个(均可读写) | 2 个(一个读,一个写) |
| 进程关系 | 需继承描述符(通常用于父子进程) | 同左 |
| 控制能力 | 支持非阻塞、信号驱动等高级选项 | 功能有限 |
常见错误处理
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
switch(errno) {
case EMFILE: // 进程描述符耗尽
perror("Too many open files");
break;
case EAFNOSUPPORT: // 不支持的协议族
perror("Unsupported address family");
break;
case EPROTONOSUPPORT: // 不支持的协议
perror("Unsupported protocol");
break;
default:
perror("socketpair");
}
exit(EXIT_FAILURE);
}注意事项
- 描述符关闭
- 通信双方需显式关闭未使用的描述符(避免资源泄漏)。
- 协议族限制
- 可移植代码应仅使用
AF_UNIX(其他协议族如AF_INET可能不被支持)。
- 可移植代码应仅使用
- 阻塞与非阻塞
- 默认阻塞模式,可通过
fcntl(fd, F_SETFL, O_NONBLOCK)或SOCK_NONBLOCK标志设为非阻塞。
- 默认阻塞模式,可通过
- 进程关系
- 套接字对只能在有亲缘关系的进程间继承(或通过
sendmsg()传递描述符)。
- 套接字对只能在有亲缘关系的进程间继承(或通过
适用场景对比
| 场景 | 推荐方法 |
|---|---|
| 父子进程双向通信 | socketpair() |
| 无亲缘关系进程通信 | 命名 Unix 套接字 |
| 简单单向数据流(如日志) | pipe() |
| 高性能 IPC(Linux 特有) | eventfd()/signalfd() |
socketpair() 是进程间双向通信的轻量级解决方案,结合了管道的易用性和套接字的灵活性,尤其适合需要在亲缘进程间高效传递数据的场景。
到此这篇关于c++中socketpair函数示例详解的文章就介绍到这了,更多相关c++ socketpair函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
