Linux下socketpair系统API调用使用说明
目录
1.socketpair函数说明
2.socketpair使用举例
在阅读nginx源码时,发现其调用socketpair来实现master和worker进程之间进行数据交互。其代码如下:
思考:master和worker进程是父子关系,有亲属关系的进程通过pipe/pipe2(匿名管道)和mkfifo(有名管道)也能实现数据传输,为什么要使用socketpair来进行数据交互?
原因:socketpair创建的全双工的一对套接字,而匿名管道和有名管道是单工的。
匿名管道和有名管道使用可以参考如下博客:
https://www.cnblogs.com/fortunely/p/14648146.html
1.socketpair函数说明
socketpair创建管道之后,fds[0]和fds[1]均可以读写,读写可发生在一个线程中,也可以发生在父子进程之间。关于socketpair使用,可参考如下说明:
SOCKETPAIR(2) Linux Programmer's Manual SOCKETPAIR(2)
NAME
socketpair - create a pair of connected socketsSYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int socketpair(int domain, int type, int protocol, int sv[2]);
DESCRIPTION
The socketpair() call creates an unnamed pair of connected sockets in the specified domain, of the specified type, and using the optionally specified protocol. For further details of these
arguments, see socket(2).The file descriptors used in referencing the new sockets are returned in sv[0] and sv[1]. The two sockets are indistinguishable.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.On Linux (and other systems), socketpair() does not modify sv on failure. A requirement standardizing this behavior was added in POSIX.1-2016.
ERRORS
EAFNOSUPPORT
The specified address family is not supported on this machine.EFAULT The address sv does not specify a valid part of the process address space.
EMFILE The per-process limit on the number of open file descriptors has been reached.
ENFILE The system-wide limit on the total number of open files has been reached.
EOPNOTSUPP
The specified protocol does not support creation of socket pairs.EPROTONOSUPPORT
The specified protocol is not supported on this machine.CONFORMING TO
POSIX.1-2001, POSIX.1-2008, 4.4BSD. socketpair() first appeared in 4.2BSD. It is generally portable to/from non-BSD systems supporting clones of the BSD socket layer (including System V
variants).NOTES
On Linux, the only supported domain for this call is AF_UNIX (or synonymously, AF_LOCAL). (Most implementations have the same restriction.)Since Linux 2.6.27, socketpair() supports the SOCK_NONBLOCK and SOCK_CLOEXEC flags in the type argument, as described in socket(2).
POSIX.1 does not require the inclusion of <sys/types.h>, and this header file is not required on Linux. However, some historical (BSD) implementations required this header file, and portable
applications are probably wise to include it.

2.socketpair使用举例
2.1 如下代码演示阻塞和非阻塞socketpair使用:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>int parentProcess(int* fds, int num) {if (num < 2) {return -1;}char buf[128] {0};recv(fds[0], buf, 128, 0);printf("parent:: %s\n", buf);recv(fds[0], buf, 128, 0);printf("parent:: %s\n", buf);sleep(1);recv(fds[0], buf, 128, 0);printf("parent:: %s\n", buf);sleep(1);memset(buf, 0x00, sizeof(buf));strcpy(buf, "hello child, I am parent !");send(fds[1], buf, strlen(buf), 0);close(fds[0]);close(fds[1]);return 0;
}int childProcess(int* fds, int num) {if (num < 2) {return -1;}char buf[128] = "hello parent, I am child";send(fds[1], buf, strlen(buf), 0);sleep(1);send(fds[1], buf, strlen(buf), 0);sleep(1);char *pStr = (char*)"给父进程再发一次消息";send(fds[1], pStr, strlen(pStr), 0);memset(buf, 0x00, sizeof(buf));sleep(1);recv(fds[0], buf, 128, 0);printf("child:: %s\n", buf);close(fds[0]);close(fds[1]);return 0;
}//设置文件描述符非阻塞
int fd_nonblocking(int s)
{int  nb;nb = 1;//方法一/*int flag = fcntl(s, F_GETFL);flag |= O_NONBLOCK;return fcntl(s, F_SETFL, flag);*///方法二return ioctl(s, FIONBIO, &nb);
}int close_channel(int* fds) {if (close(fds[0]) == -1) {printf("close() channel fds[0] failed\n");}if (close(fds[1]) == -1) {printf("close() channel fds[1] failed\n");}return 0;
}void testNonblockingSocketFd(int* fds) {if (-1 == fd_nonblocking(fds[0])) {printf("fd_nonblocking fds[0] failed\n");close_channel(fds);}if (-1 == fd_nonblocking(fds[1])) {printf("fd_nonblocking fds[1] failed\n");close_channel(fds);}
}int main()
{int fds[2];// fds[0]: 读  fds[1]: 写 socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
#ifdef NOBLOCKFDtestNonblockingSocketFd(fds);
#endifint pid = fork();printf("parent: %d, child: %d\n", getpid(), pid);switch (pid) {case -1: // errorreturn -1;case 0: // childchildProcess(fds, 2);printf("child exit \n");break;default: // parentparentProcess(fds, 2);printf("parent exit \n");break;}return 0;
}
阻塞应用:

非阻塞应用:

通过非阻塞应用发现, 父进程退出后,子进程往管道发送数据后,接着自己读到了发送的数据。
2.2只使用一端进行读写
如2.1可以发现fds[0]和fds[1]均可以读写,那么自己进程读到的可能是别的进程发来的数据,也可能是自己进程发来的数据,编程逻辑很不清晰。
常用的方式是:
(1) 父进程 close(fd[0]),使用fd[1]读写,子进程close(fd[1]),使用fd[0]读写
(1) 父进程 close(fd[1]),使用fd[0]读写,子进程close(fd[0]),使用fd[1]读写
如下代码显示情形(1)
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>int parentProcess(int* fds, int num) {if (num < 2) {return -1;}close(fds[0]); // 关闭fds[0] 使用fds[1]读写,子进程中关闭fds[1] 使用fds[0]读写char buf[128] {0};char *pStr = (char*)"hello child, I am parent";int inum = 0;while (inum++ < 10) {memset(buf, 0x00, sizeof(buf));//写write(fds[1], pStr, strlen(pStr));//读read(fds[1], buf, 128);printf("parent收到child的招呼 %d :: %s\n", inum, buf);sleep(1);}close(fds[1]);return 0;
}int childProcess(int* fds, int num) {if (num < 2) {return -1;}close(fds[1]);char buf[128] {0};char *pStr = (char*)"hello parent, I am child";int inum = 0;while (inum++ < 10) {memset(buf, 0x00, sizeof(buf));//读read(fds[0], buf, 128);printf("child收到paren的招呼 %d :: %s\n", inum, buf);//写write(fds[0], pStr, strlen(pStr));sleep(1);}close(fds[0]);return 0;
}//设置文件描述符非阻塞
int fd_nonblocking(int s)
{int  nb;nb = 1;//方法一/*int flag = fcntl(s, F_GETFL);flag |= O_NONBLOCK;return fcntl(s, F_SETFL, flag);*///方法二return ioctl(s, FIONBIO, &nb);
}int close_channel(int* fds) {if (close(fds[0]) == -1) {printf("close() channel fds[0] failed\n");}if (close(fds[1]) == -1) {printf("close() channel fds[1] failed\n");}return 0;
}void testNonblockingSocketFd(int* fds) {if (-1 == fd_nonblocking(fds[0])) {printf("fd_nonblocking fds[0] failed\n");close_channel(fds);}if (-1 == fd_nonblocking(fds[1])) {printf("fd_nonblocking fds[1] failed\n");close_channel(fds);}
}int main()
{int fds[2];socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
#ifdef NOBLOCKFDtestNonblockingSocketFd(fds);
#endifint pid = fork();printf("parent: %d, child: %d\n", getpid(), pid);switch (pid) {case -1: // errorreturn -1;case 0: // childchildProcess(fds, 2);printf("child exit \n");break;default: // parentparentProcess(fds, 2);printf("parent exit \n");break;}return 0;
}
运行结果如下:

2.3一个master多个worker数据收发
如下代码模拟nginx中一个 master进程,多个worker进程进行数据交互
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>int parentProcess(int* fds, int num) {if (num < 2) {return -1;}close(fds[0]); // 关闭fds[0] 使用fds[1]读写,子进程中关闭fds[1] 使用fds[0]读写char buf[128] {0};char *pStr = (char*)"hello child, I am parent";int inum = 0;while (inum++ < 3) {memset(buf, 0x00, sizeof(buf));//写write(fds[1], pStr, strlen(pStr));//读read(fds[1], buf, 128);printf("parent [%d] %d :: %s\n", getpid(), inum, buf);sleep(1);}close(fds[1]);return 0;
}int childProcess(int* fds, int num) {if (num < 2) {return -1;}close(fds[1]);char buf[128] {0};char *pStr = (char*)"hello parent, I am child";char sendBuf[128] = {0};sprintf(sendBuf, "hello parent, I am child %d", getpid());int inum = 0;while (inum++ < 3) {memset(buf, 0x00, sizeof(buf));//读read(fds[0], buf, 128);printf("child [%d] %d :: %s\n", getpid(), inum, buf);//写write(fds[0], sendBuf, strlen(sendBuf));sleep(1);}close(fds[0]);return 0;
}//设置文件描述符非阻塞
int fd_nonblocking(int s)
{int  nb;nb = 1;//方法一/*int flag = fcntl(s, F_GETFL);flag |= O_NONBLOCK;return fcntl(s, F_SETFL, flag);*///方法二return ioctl(s, FIONBIO, &nb);
}int close_channel(int* fds) {if (close(fds[0]) == -1) {printf("close() channel fds[0] failed\n");}if (close(fds[1]) == -1) {printf("close() channel fds[1] failed\n");}return 0;
}void testNonblockingSocketFd(int* fds) {if (-1 == fd_nonblocking(fds[0])) {printf("fd_nonblocking fds[0] failed\n");close_channel(fds);}if (-1 == fd_nonblocking(fds[1])) {printf("fd_nonblocking fds[1] failed\n");close_channel(fds);}
}struct TDataExchangeChannel {int fds[2];
};#define GROUP_NUM 2int main()
{
#ifdef NOBLOCKFDtestNonblockingSocketFd(fds);
#endifTDataExchangeChannel channels[GROUP_NUM];for (int i = 0; i < GROUP_NUM; i++) {socketpair(PF_UNIX, SOCK_STREAM, 0, channels[i].fds);int pid = fork();switch (pid) {case -1: // errorreturn -1;case 0: // childchildProcess(channels[i].fds, 2);printf("child exit \n");exit(0);default: // parentbreak;}}//父进程给子进程发送消息,并接收子进程发来的消息for (int i = 0; i < GROUP_NUM; i++) {parentProcess(channels[i].fds, 2);}return 0;
}
运行效果如下:

根据运行结果看,master进程为31558,两个子进程为31559,31560,master进程可以分别与两个worker进行数据收发。
相关文章:
 
Linux下socketpair系统API调用使用说明
目录 1.socketpair函数说明 2.socketpair使用举例 在阅读nginx源码时,发现其调用socketpair来实现master和worker进程之间进行数据交互。其代码如下: 思考:master和worker进程是父子关系,有亲属关系的进程通过pipe/pipe2&#x…...
【Netty】Future 源码分析(十六)
文章目录 前言一、JDK 的 Future 接口二、Netty 的 Future 接口三、ChannelFuture 接口总结 前言 回顾Netty系列文章: Netty 概述(一)Netty 架构设计(二)Netty Channel 概述(三)Netty Channel…...
 
5月《中国数据库行业分析报告》正式发布,首发时序、实时数据库两大【全球产业图谱】
为了帮助大家及时了解中国数据库行业发展现状、梳理当前数据库市场环境和产品生态等情况,从2022年4月起,墨天轮社区行业分析研究团队出品将持续每月为大家推出最新《中国数据库行业分析报告》,持续传播数据技术知识、努力促进技术创新与行业生…...
 
【计算机视觉 | 目标检测】术语理解6:ViT 变种( ViT-H、ViT-L ViT-B)、bbox(边界框)、边界框的绘制(含源代码)
文章目录 一、ViT & ViT变种1.1 ViT的介绍1.2 ViT 的变种 二、bbox(边界框)三、边界框的绘制 一、ViT & ViT变种 1.1 ViT的介绍 ViT,全称为Vision Transformer,是一种基于Transformer架构的视觉处理模型。传统的计算机视…...
 
为kong网关添加限流插件
限流用于控制发送到上游服务的请求速率。 它可用于防止 DoS 攻击、限制网络抓取和其他形式的过度使用。 如果没有速率限制,客户可以无限制地访问您的上游服务,这可能会对可用性产生负面影响。 一、全局范围内的限流 1、启用限流 [rootmin ~]# curl -i…...
 
Python接口自动化—接口测试用例和接口测试报告模板
简介 当今社会在测试领域,接口测试已经越来越多的被提及,被重视,而且现在好多招聘信息要对接口测试提出要求。区别于传统意义上的系统级别测试,很多测试人员在接触到接口测试的时候,也许对测试执行还可以比较顺利的上…...
C++无锁队列
C无锁队列是一种多线程编程技术,它可以在不使用锁的情况下实现线程安全的队列。它可以提高多线程程序的性能。 无锁队列的主要思想是让多个线程同时访问队列,而不需要使用锁来保护共享资源。这可以避免锁竞争和死锁等问题,从而提高程序的效率…...
MySQL 5.7 修改账号密码
MySQL 5.7 修改账号密码 1、概述2、更改密码2.1、寻找命令2.2、补充 3、总结 1、概述 大家好,我是欧阳方超。 MySQL数据库安装后设置的密码太简单了, 近期安全检查,这种弱密码全部得修改,好吧那就开始改吧 2、更改密码 2.1、寻…...
ARM实验6-基于中断的按键处理程序实验
一、实验名称:基于中断的按键处理程序实验 二、实验目的: 1.掌握ARM处理器的中断处理过程。 2.掌握ARM处理器中断服务程序的编写方法。 3.通过该编程实验,进一步巩固和强化学生ARM汇编编程的能,ARM应用程序框架,培养学生实际应用的能力。 三、实验内容: 按下面电路图,…...
 
安全认证:
1. 认证概述 为什么要有认证? 防止非法路由器接入企业内网的ospf路由器,保护内网安全 2. 认证方式 认证方式分为接口认证和区域认证,接口认证和区域认证没有本质的区别,接口认证是当区域内链路过多的情况下,接口认证…...
 
C++11新特性:decltype类型推导
上一节所讲的 auto,用于通过一个表达式在编译时确定待定义的变量类型,auto 所修饰的变量必须被初始化,编译器需要通过初始化来确定 auto 所代表的类型,即必须要定义变量。若仅希望得到类型,而不需要(或不能)定义变量的…...
linux下DD 命令常用操作 —— 筑梦之路
DD命令介绍 dd命令是LINUX下的一个命令行工具,用于数据转换和处理。dd代表“数据复制”,它可以从一个设备或文件中读取数据,然后将数据写入到另一个设备或文件中。dd命令可以用于多种用途,包括以下几个方面: 磁盘备份…...
android 12.0状态栏高度为0时,系统全局手势失效的解决方案
1.概述 在12.0的framework 系统全局手势事件也是系统非常重要的功能,但是当隐藏状态栏, 当把状态栏高度设置为0时,这时全局手势事件失效,这就要从系统手势滑动流程来分析 看怎么样实现系统手势功能的,然后根据功能做修改 2. 状态栏高度为0时,系统全局手势失效的解决方案…...
 
使用Jmeter进行http接口性能测试
在进行网页或应用程序后台接口开发时,一般要及时测试开发的接口能否正确接收和返回数据,对于单次测试,Postman插件是个不错的Http请求模拟工具。 但是Postman只能模拟单客户端的单次请求,而对于模拟多用户并发等性能测试…...
 
公开报名|CCPTP云渗透测试认证专家第二期培训班,将在云网基础设施安全国家工程研究中心举办
CCPTP云渗透测试认证专家由云安全联盟大中华区发布,是全球首个云渗透测试能力培养课程及人才培养认证,弥补了国内云渗透测试认知的差距和技能型人才培养的空白。4月1日-13日,CCPTP 首期班成功举办,于2023年5月10日部分学员完成考试…...
 
【App自动化测试】(十八)多设备管理平台——openSTF
目录 1. openSTF2. openSTF的安装部署2.1 MacOS2.2 Windows 3. STF操作3.1 基础操作——远程调试虚拟设备3.2 高阶操作——远程调试真机 1. openSTF OpenSTF:是一个手机设备管理平台,可以对手机进行远程管理、调试、远程手机桌面监控等操作。 特点&…...
Kafka的ACK配置含义详解
Kafka的ACK配置含义详解 Kafka producer有三种ack机制 初始化producer时在config中进行配置; 参数-1,0,1分别代表什么含义 ack等于0: 含义 意味着producer不等待broker同步完成的确认,只要继续发送下一条(批)信息 优缺点 提供了最低的…...
 
Redis主从架构、数据同步原理、全量同步、增量同步
目录 专栏导读一、Redis主从架构二、数据同步原理三、全量同步的流程三、可以从以下几个方面来优化Redis主从就集群四、全量同步和增量同步区别?五、什么时候执行全量同步?六、什么时候执行增量同步?七、超卖问题 大家好,我是哪吒…...
 
面了一个测试工程师要求月薪26K,总感觉他背了很多面试题...
最近有朋友去字节面试,面试前后进行了20天左右,包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说,80%的人都会栽在第一轮面试,要不是他面试前做足准备,估计都坚持不完后面几轮面试。 其实&…...
 
大数据简介
大数据简介 什么是大数据  最近几年,IT行业最火的名词中,少不了"大数据"、"人工智能"、"云计算"、"物联网"、"区块链"等等这些名词。针对于"大数据"这个名词,现在更是全国老…...
 
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
 
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
 
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
 
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
 
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
 
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
 
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
 
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
