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行业最火的名词中,少不了"大数据"、"人工智能"、"云计算"、"物联网"、"区块链"等等这些名词。针对于"大数据"这个名词,现在更是全国老…...

Elasticsearch数据库
目录 1. 什么是ElasticSearch1.1 概念及特点1.2 ElasticSearch适用场景概述 2. 安装ElasticSearch2.1 下载安装包2.2 环境说明2.3 创建es的用户2.4 创建es存储位置2.5 安装es2.5 修改配置文件2.6 系统优化2.7 安装jdk环境2.8 切换es用户启动数据库2.9 systemctl管理2.10 访问 3…...

Axure教程—表格(中继器)
本文将教大家如何用AXURE中的中继器制作表格 一、效果介绍 如图: 预览地址:https://oc3e6a.axshare.com 下载地址:https://download.csdn.net/download/weixin_43516258/87854863?spm1001.2014.3001.5501 二、功能介绍 可以在表格中插入…...

Linux转HTTP代理服务器
在 Linux 上搭建 HTTP 代理服务器,可以使用 Squid 或者 Nginx 等软件来实现。以下是使用 Squid 搭建 HTTP 代理服务器的步骤: 1. 安装 Squid 在终端中输入以下命令安装 Squid: sudo apt-get update sudo apt-get install squid 2. 配置 Sq…...

CPLEX Studio 集成开发环境 (IDE) 介绍
CPLEX Studio 集成开发环境 (IDE) 介绍 参考B站视频:cplex入门到精通 1.CPLEX Studio IDE 实现的功能 IBM ILOG CPLEX Studio IDE 是一个用于数学规划、约束规划以及一般组合优化应用程序的集成开发环境。 它是适用于 OPL(优化编程语言)和…...

如何在Linux机器中测试存储/磁盘I/O性能?
在Linux环境中,了解存储/磁盘I/O性能对于评估系统性能和优化存储子系统非常重要。通过测试存储/磁盘I/O性能,我们可以确定磁盘的读写速度、延迟和吞吐量等指标。本文将介绍几种常用的方法来测试Linux机器中的存储/磁盘I/O性能。 方法一:使用d…...

ChatGPT国内免费使用方法【国内免费使用地址】
当下人工智能技术的快速发展,聊天机器人成为了越来越多人们日常生活和工作中的必备工具。如何在国内免费使用ChatGPT聊天机器人,成为了热门话题。本文将为你详细介绍ChatGPT国内免费使用方法,让你轻松拥有聊天机器人助手,提高工作…...

常微分方程ODE和Neural Ordinary Differential Equations
微分方程(英語:Differential equation,DE)是一種數學方程,用來描述某一類函数與其导数之间的关系。微分方程的解是一個符合方程的函數。而在初等数学的代数方程裡,其解是常数值。 常微分方程(英…...

C++ 编译过程(附简单实例)
C 采用分离编译模式,分离编译指的是,一个程序/项目是由若干个源文件共同实现,编译时先把每个源文件单独编译生成目标文件,再将所有目标文件连接起来,形成单一的可执行文件。 C 编译的四个阶段:预处理、编译…...

ThingsBoard教程(五四):规则节点解析 Azure IoT Hub Node, RabbitMQ Node
Azure IoT Hub Node Since TB Version 2.5.3 配置 主题 - 获取有关IoT Hub主题的更多信息,请使用以下链接。主机名 - Azure IoT Hub主机名。设备ID - 来自Azure IoT Hub的设备ID。凭据 - Azure IoT Hub连接凭据。可以是共享访问签名或PEM格式证书。Azure IoT Hub支持不同的…...

元素偏移量offset
文章目录 1. offset概述2. offset与style的区别 1. offset概述 offset就是偏移量,我们使用offset系列相关属性可以动态的得到该属性的位置(偏移)、大小等。 element.offsetParent 返回作为该元素带有定位的父级元素,如果父级都没…...