当前位置: 首页 > news >正文

Linux下的系统编程——进程间的通信(九)

 一、进程间通信常用方式

IPC方式:

        Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
 

        在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有:


1.管道(使用最简单)

2.信号(开销最小)

3.共享映射区(无血缘关系)

4.本地套接字(最稳定)

二、管道

1.概念:

      

         管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:


(1).其本质是一个伪文件(实为内核缓冲区)

(2).由两个文件描述符引用,一个表示读端,一个表示写端,只能一次读取

(3).规定数据从管道的写端流入管道,从读端流出,单向流动


管道的原理:  管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现

管道的:

        1)数据不能进程自己写,自己读。·

        2)管道中数据不可反复读取。一旦读走,管道中不再存在。

        3)采用半双工通信方式,数据只能在单方向上流动

        4)只能在有公共祖先的进程间使用管道

常用的通信方式: 单工通信、半双工通信、全双工通信

创建管道文件:

(不占用磁盘空间)

*2.pipe函数:

函数功能:创建,并打开管道。

    int pipe(int fd[2]);

    参数:    

        fd[0]: 读端。

        fd[1]: 写端。

    返回值:

         成功: 0

         失败: -1 errno

管道通信:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{int ret,re;int fd[2];pid_t pid;char *str = "hello pipe\n";char buf[1024];ret = pipe(fd);if(ret == -1)sys_err("pipe error");pid = fork();if(pid > 0){            //父进程close(fd[0]);       //关闭读段write(fd[1],str,strlen(str));//写入数据sleep(1);close(fd[1]);            //关闭写段}else if(pid == 0){        //子进程close(fd[1]);          //关闭写段re = read(fd[0],buf,sizeof(buf)); //读取数据write(STDOUT_FILENO,buf,re);      //写到屏幕上close(fd[0]);        //关闭读段}return 0;}

*3.管道的读写行为:

读管道:
        1. 管道有数据,read返回实际读到的字节数。

        2. 管道无数据:    

                        1)无写端,read返回0 (类似读到文件尾)

                        2)有写端,read阻塞等待。

写管道:
        1. 无读端, 异常终止。 (SIGPIPE导致的)

        2. 有读端:    

                        1) 管道已满, 阻塞等待

                        2) 管道未满, 返回写出的字节个数。

 1)读管道,管道无数据(无写端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{int ret,re;int fd[2];pid_t pid;char *str = "hello pipe\n";char buf[1024];ret = pipe(fd);if(ret == -1)sys_err("pipe error");pid = fork();if(pid > 0){            //父进程close(fd[0]);       //关闭读段//	write(fd[1],str,strlen(str));//写入数据close(fd[1]);            //关闭写段}else if(pid == 0){        //子进程close(fd[1]);          //关闭写段re = read(fd[0],buf,sizeof(buf)); //读取数据printf("child read ret =%d\n",ret);write(STDOUT_FILENO,buf,re);      //写到屏幕上close(fd[0]);        //关闭读段}return 0;}

read返回0

4.父子间进程 :

        使用管道实现父子进程间通信,完成:ls | wc -l。假定父进程实现ls,子进程实现wc

ls | wc -l命令:

 实现流程:

(1)父进程创建管道 pipe()

(2)父进程创建子进程 fork()

(3)设置父进程执行ls命令,子进程执行wc命令 execlp()

(4)设置父子进程通过管道的单项流动(设置指向标准输出的指向管道dup2()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{/***************dup2();fork();pipe();execlp();****************/int fd[2]; int ret;pid_t pid;//父进程创建管道ret = pipe(fd);if(ret == -1){sys_err("pipe error");}//父进程创建子进程 pid = fork();if(pid == -1){sys_err("fork error");}else if(pid > 0){close(fd[1]);                  //关闭写,设置单项流动dup2(fd[0],STDIN_FILENO);      //设置读管道信息execlp("wc","wc","-l",NULL);        //设置子进程wc命令sys_err("execlp wc error");}else if(pid == 0){close(fd[0]);                  //关闭读,设置单项流动dup2(fd[1],STDOUT_FILENO);     //设置写操作指向管道execlp("ls","ls",NULL);        //设置父进程执行ls命令sys_err("execlp ls error");}return 0;
}

 

 5.兄弟间进程通信:

使用管道实现兄弟进程间通信,完成:ls | wc -l。假定父进程实现ls,子进程实现wc

 实现流程:

(1)父进程创建管道 pipe()

(2)父进程创建俩个(兄弟)子进程 fork()

(3)设置兄进程执行ls命令,第进程执行wc命令 execlp() 

(4)设置兄弟进程通过管道的单项流动(设置指向标准输出的指向管道dup2()

(5)回收父进程残余文件  wait()

刚创建出的兄弟进程:

 设置兄弟进程通过管道的单项流动后

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{/***************dup2();fork();pipe();execlp();wait();****************/int fd[2]; int ret;int i;pid_t pid;//父进程创建管道ret = pipe(fd);if(ret == -1){sys_err("pipe error");}for(i = 0;i < 2;i++){       //表达式2 出口,仅限父进程使用pid = fork();if(pid == -1){sys_err("fork error");}if(pid == 0)           //子进程出口break;}if(i == 2){                //父进程 //不需要父进程所以需要关闭他的读写并且回收掉父进程close(fd[0]);          close(fd[1]);wait(NULL);wait(NULL);}else if(i == 0){          //兄进程close(fd[0]);dup2(fd[1],STDOUT_FILENO);execlp("ls","ls",NULL);    //兄进程执行ls命令sys_err("ececlp ls error");}else if(i == 1){		   //弟进程close(fd[1]);dup2(fd[0],STDIN_FILENO);execlp("wc","wc","-l",NULL);//弟进程执行wc命令sys_err("ececlp wc error");}return 0;
}

6.多个读写端操作管道

实现一个pipe有一个写端,多个读端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{/***************dup2();fork();pipe();execlp();****************/int fd[2],i,n; int ret;char buf[1024];pid_t pid;//父进程创建管道ret = pipe(fd);if(ret == -1){sys_err("pipe error");exit(1);}for(i = 0;i < 2;i++){pid = fork();if(pid == -1){sys_err("fork error");exit(1);}if(pid == 0)break;}if(i == 2){            //父进程close(fd[1]);       //父进程关闭写端,留读端读取数据sleep(1);n = read(fd[0],buf,1024);    //从管道中读取数据write(STDOUT_FILENO,buf,n); for(i == 0;i < 2;i++)        //两个儿子wait两次wait(NULL);}else if(i == 0){        //兄进程close(fd[0]);write(fd[1],"1.hello\n",strlen("1.hello\n"));}else if(i == 1){		 //弟进程close(fd[0]);write(fd[1],"2.world\n",strlen("2.world\n"));}return 0;
}

7.管道缓冲区大小:

可以使用 ulimIt -a 命令来查看当前系统中创建管道文件所对应的内核缓冲区大小。通常为:
        pipe size               ......(512 bytes,-p)  8 

也可以使用fpathconf函数,借助参数―选项来查看。使用该宏应引入头文件<unistd.h>
        long fpathconf(int fd, int name);成功:返回管道的大小―失败:-1,设置errno

.8.管道的优劣

优点:简单,相比信号,套接字实现进程间通信,简单很多。

缺点:

                1.只能单向通信,双向通信需建立两个管道。
                2.只能用父子、兄弟进程(有共同祖先)间通信。该问题后来使用fifo有名管道解决)

 三、FIFO:   

fifo管道:可以用于无血缘关系的进程间通信。

    命名管道:  mkfifo 

    无血缘关系进程间通信:

                        读端,open fifo O_RDONLY

                        写端,open fifo O_WRONLY

     

1.命名管道fifo的创建和原理:

使用命令:myfifo myfifo

 使用myfifo创建

#include<stdio.h>
#include<sys/stat.h>
#include<errno.h>
#include<pthread.h>
#include<stdlib.h>void sys_err(const char *str){perror(str);exit(1);
}int main(int argc,char *str)
{int ret = mkfifo("mytestfifo",0664);if(ret == -1)sys_err("mkfifo error");return 0;}

相关文章:

Linux下的系统编程——进程间的通信(九)

一、进程间通信常用方式 IPC方式&#xff1a; Linux环境下&#xff0c;进程地址空间相互独立&#xff0c;每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到&#xff0c;所以进程和进程之间不能相互访问&#xff0c;要交换数据必须通过内核&am…...

Qt QtableWidget、QtableView表格删除选中行、删除单行、删除多行

文章目录 Qt QtableWidget表格删除选中行只能选择一行&#xff0c;点击按钮后&#xff0c;删除一行可以选择中多行&#xff0c;点击按钮后&#xff0c;删除多行选中某一列中的不同行&#xff0c;点击按钮后&#xff0c;删除多行 QTableWidgetSelectionRange介绍QTableWidget的选…...

【代码随想录day24】不同的二叉搜索树

题目 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xf…...

数学建模--Subplot绘图的Python实现

目录 1.Subplot函数简介 2.Subplot绘图范例1:绘制规则子图 3.Subplot绘图范例2:绘制不规则子图 4.Subplot绘图范例3:gridspec辅助实战1 5.Subplot绘图范例4:gridspec辅助实战2 1.Subplot函数简介 """ 最近在数学建模种需要绘制多张子图,发现对于subplot函…...

JMeter(三十九):selenium怪异的UI自动化测试组合

文章目录 一、背景二、JMeter+selenium使用过程三、总结一、背景 题主多年前在某社区看到有人使用jmeter+selenium做UI自动化测试的时候,感觉很是诧异、怪异,为啥?众所周知在python/java+selenium+testng/pytest这样的组合框架下,为啥要选择jmeter这个东西[本身定位是接口测…...

c++ 移动构造方法为什么要加noexcept

背景: 最近看了候捷老师的c的教程, 他说移动构造方法要加noexcept, 在vector扩容的时候, 如果有移动构造方法没有加noexcept,是不会调用的. 个人感觉有些神奇, 这就去查下一探究竟. 过程: 测试代码如下: #include <iostream> #include <vector> struct A {A(){s…...

鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…...

手把手教你搭建园林园艺小程序商城

现如今&#xff0c;随着互联网的快速发展&#xff0c;小程序成为了企业和个人展示产品和服务的新方式。在园林园艺行业&#xff0c;构建一个园林园艺小程序能够更好地推广和销售自己的产品和服务。那么&#xff0c;如何构建一个园林园艺小程序呢&#xff1f;下面我们来详细介绍…...

Java Iterator(迭代器)

Java迭代器&#xff08;Iterator&#xff09;是 Java 集合框架中的一种机制&#xff0c;是一种用于遍历集合&#xff08;如列表、集合和映射等&#xff09;的接口。 它提供了一种统一的方式来访问集合中的元素&#xff0c;而不需要了解底层集合的具体实现细节。 Iterator 是 …...

Logstash同步MySQL数据到ElasticSearch

当MySQL数据到一定的数量级&#xff0c;而且索引不能实现时&#xff0c;查询就会变得非常缓慢&#xff0c;所以使用ElasticSearch来查询数据。本篇博客介绍使用Logstash同步MySQL数据到ElasticSearch&#xff0c;再进行查询。 测试环境 Windows系统MySQL 5.7Logstash 7.0.1El…...

【C++】运算符重载的示例实现和应用

C运算符重载的格式&#xff1a; operator 运算符 比如要重载 ! 运算符 &#xff1a; operator ! 下面是一个例子&#xff1a; class DemoText{DemoText(string str, int num){m_text str; m_number num;}string m_text;int m_number; }这里来定义两个对象&#xff1a;…...

Kubernetes禁止调度

在Kubernetes中&#xff0c;您可以通过几种方式来禁止某个Pod调度到节点上。以下是一些方法&#xff1a; Node Selector&#xff1a;您可以使用Node Selector来限制Pod只能调度到带有特定标签的节点上。如果您希望完全禁止Pod调度到某些节点上&#xff0c;可以确保这些节点不拥…...

CocosCreator3.8研究笔记(七)CocosCreator 节点和组件的介绍

相信很多新手朋友&#xff0c;肯定会问&#xff0c;CocosCreator 中什么是节点&#xff1f;什么是组件&#xff1f; 一、什么是组件&#xff08;Component&#xff09;&#xff1f; Cocos Creator 3.8 的工作流程是以组件式开发为核心&#xff0c;即以组合而非继承的方式进行游…...

Ceph入门到精通-C++入门知识点

C中的双冒号(::)是作用域分解运算符&#xff08;scope resolution operator&#xff09;。 它主要有以下两种用法&#xff1a; 用于区分同名的不同成员&#xff0c;例如在不同类中声明了同名的成员函数或成员变量&#xff0c;可以使用A::B的方式来特指A类的B成员。当全局变量…...

Ansible之playbook详解和应用实例

目录 一、playbook简介 1.什么是playbook 2.playbook组成 二、应用实例 1.使用playbook安装启用httpd服务 2.使用playbook安装启用nginx服务 三、ansible-playbook其他用法 1.检查yaml文件的语法是否正确 2.检查tasks任务 3.检查指定的主机 4.指定从某个task开始运行…...

经验萃取方法

【经验萃取】 经验萃取不是简单的总结提炼归纳&#xff01; 经验萃取需经过还原、复盘分析、萃取重构 一.经验萃取前三个准备 1.定主题&#xff1a; 萃取主题选择&#xff08;阐述原因、确定级别、差距/问题是源头&#xff09;->多维评分&#xff1a;普遍性、重要性、迫切…...

手写apply方法

<script>/** 手写apply方法 * */Function.prototype.myApply function (context, args) {console.log(this, sss)//fnconst key Symbol()context[key] thiscontext[key](...args)delete context[key]return context[key]}const obj {name: zs,age: 18}function fn …...

Jenkins实现基础CD操作

操作截图 在Jenkins里面设置通过标签进行构建 在Jenkins中进入项目&#xff0c;配置以下 将execute shell换到invoke top-level maven targets之前 在gitlab中配置标签 代码迭代新的版本 项目代码迭代 修改docker-compose.yml 提交新版本的代码 在Jenkins中追加新…...

开源软件合集(Docker)

Docker安装 1.安装命令&#xff1a;curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun2.启动&#xff1a;systemctl start docker3.停止&#xff1a;systemctl stop docker4.重启&#xff1a;systemctl restart docker5.开机启动&#xff1a;systemctl enab…...

Ceph入门到精通-生产日志级别设置

Ceph 子系统及其日志记录级别的信息。 了解 Ceph 子系统及其日志记录级别 Ceph 由多个子系统组成&#xff1a; 每个子系统都有其日志记录级别&#xff1a; 默认情况下存储在 /var/log/ceph/ 目录中的输出日志&#xff08;日志级别&#xff09;存储在内存缓存中的日志&#…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...