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

news2024/11/26 12:18:47

 一、进程间通信常用方式

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;
	
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/980070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

螺母加工工艺流程

螺母是具有内螺纹并与螺栓配合使用的紧固件,具有内螺纹并与螺杆配合使用用以传递运动或动力的机械零件&#xff0c;是自动化行业中的重要传动零部件之一。大家知道螺母的加工工艺吗&#xff1f; 一般来说&#xff0c;螺母的加工工艺流程包括原材料采购、初加工、调质、精加工、…

vue基础知识六:v-show和v-if有什么区别?使用场景分别是什么?

一、v-show与v-if的共同点 我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含v-else)&#xff0c;都能控制元素在页面是否显示 在用法上也是相同的 <Model v-show"isShow" /> <Model v-if"isShow" />当表达式为true的时候&#…

网管实战⑼:配置华为S5720交换机

配置好汇聚交换机后&#xff0c;需要根据单位情况配置具体的接入交换机。 自从2019年12月底配置好交换机后&#xff0c;基本上都没有怎么操作交换机了。那时候使用的是H3C交换机&#xff0c;主要是H3C S7706、H3C S5120、H3C S5130、H3C S5500、H3C S3600等型号的交换机&#x…

微信公众号从0到1开发

之前做项目有就接触微信公众号的接入&#xff0c;但没有将过程记录成笔记&#xff0c;这几天在做的项目也是需要集成微信公众号&#xff0c;正好将在做的过程记录成笔记 文章目录 0、准备工作一、公众号平台1、参数解释2、获取域名 二、后端配置 一、第一阶段-公众号接入1、接…

第4节-PhotoShop基础课程-Ps格式

文章目录 前言1.像素认识2. 图层认识1.图层有上下前后遮挡关系2.橡皮檫可以擦掉选择图层的像素3.新建图层4.新建删除图层 3. 分辨率的理解4. 图片格式A 前言 本章主要介绍PS常用格式 1.像素认识 下面每个格子就是像素 2. 图层认识 1.图层有上下前后遮挡关系 2.橡皮檫可以擦…

elk安装篇之 Kibana安装

Kibana是一个开源的分析与可视化平台&#xff0c;设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看存放在Elasticsearch中的数据。是es的可视化客户端之一。 一&#xff1a;下载 https://www.elastic.co/cn/kibana 我的es是elasticsearch-7.10.2版本&#x…

MQ解决重复消费问题

1. 消息重复消费概述 重复消费一直是行业内重视的问题&#xff0c;在当下的互联网时代&#xff0c;追求的是高效&#xff0c;安全&#xff0c;准确的数据交互。对于大型项目来讲&#xff0c;数据量数以亿计&#xff0c;那么这些数据如何确保安全准确&#xff0c;同时又不失效率…

用AI数字人视频带货新玩法教程

本期是赤辰第26期AI项目教程&#xff0c;底部准备了9月粉丝福利&#xff0c;可以免费领取。 今天给大家分享的AI项目是用AI数字人图文带货账号案例&#xff0c;这个账号是我2周前刷到的&#xff0c;今早闲着无事又刷到了这个账号数据已经飞起来了&#xff0c;第一条视频是8月1…

webhook--详解(gitee 推送)

一、简介 webhook 是一种基于 HTTP 的回调函数&#xff0c;可在 2 个应用编程接口&#xff08;API&#xff09;之间实现轻量级的事件驱动通信。是一种新型的前后端交互方式&#xff0c;一种对客户端-服务器模式的逆转&#xff0c;在传统方法中&#xff0c;客户端从服务器请求数…

提货卡礼品卡免登录提货程序开发

提货卡礼品卡免登录多活动H5小程序开发 适用于公司福利礼品卡提货&#xff0c;礼品公司提货卡。 功能&#xff1a; 支持多平台&#xff1a;基于Uniapp开发&#xff0c;可编译H5、微信小程序。 商品库模式&#xff1a;提货活动创建可以设置从商品库选择本活动可选的商品&am…

RKNPU2通用API和零拷贝API

RKNPU2通用API 通用API接口按照异构编程规范&#xff0c;需要将数据拷贝到NPU运行时的内存空间。 通用API部署流程 初始化上下文&#xff0c;需要先创建上下文对象和读取模型文件 rknn_context ctx; model load_model(model_path, &model_len); ret rknn_init(&ctx…

集合的进阶学习

集合体系结构 Collection 单列集合 包含List Set List 包含ArrayList LinkedList Set包含HashSet TreeSet HashSet包含LinkedHashSet List系列集合&#xff1a;添加的元素是有序的、可重复、有索引 Set系列集合&#xff1a;添加的元素是无序的、不重复、无索引 Collectio…

华为云云服务器评测|在Docker环境下部署Mysql数据库

华为云云服务器评测&#xff5c;在Docker环境下部署Mysql数据库 一、前言1.1 云耀云服务器L实例简介1.2 Mysql数据库简介 二、本次实践介绍2.1 本次实践简介2.2 本次环境规划 三、购买云耀云服务器L实例3.1 登录华为云3.2 购买云耀云服务器L实例3.3 查看云耀云服务器L实例状态3…

Windows wsl2安装Ubuntu

wsl&#xff08;Windows Subsystem for Linux&#xff09;即适用于Windows的Linux子系统&#xff0c;是一个实现在Windows 10 / 11上运行原生Linux的技术。 wsl2 为其迭代版本&#xff0c;可以更好的在Windows上运行Linux子系统。 这里以 Windows 11 安装Ubuntu作为示例。 开启…

浅识java多线程

目录 一 进程和线程定义 二 创建线程的种类 &#xff08;1&#xff09;继承java.lang.Thread &#xff08;2&#xff09;实现java.lang.Runnable接口 三 多线程 &#xff08;1&#xff09;继承java.lang.Thread多线程 &#xff08;2&#xff09;实现java.lang.Runnable…

vmware fusion12共享文件夹到虚拟机window10

文章目录 一、window10虚拟机安装VMware Tools二、MAC配置共享文件夹三、使用 一、window10虚拟机安装VMware Tools vmware fusion—虚拟机----安装VMware Tools–一路下一步 确认安装 双击进行安装 一路下一步&#xff0c;傻瓜式安装 二、MAC配置共享文件夹 设置—系…

2023年高教社杯全国大学生数学建模竞赛参赛事项注意

MathClub数模资源&#xff0c;含专属思路 资源链接&#xff1a;点击这里获取众多数模资料、思路精讲、论文模板latex和word、学习书籍等 2023高教社杯数学建模国赛–赛前准备 一年一度的数学建模国赛要来啦&#xff01;&#xff01;&#xff01;小编仔细阅读了比赛官方网站上…

【Java】线程都有哪几种状态

文章目录 前言传统线程模型&#xff08;操作系统&#xff09;中线程状态Java线程中的状态线程的运行流程 前言 首先我们要知道&#xff0c;在传统&#xff08;操作系统&#xff09;的线程模型中线程被分为五种状态&#xff0c;在java线程中&#xff0c;线程被分为六种状态。 …

使用客户支持自动化,您的电子商务收益稳了

经营电子商务业务涉及处理各种任务&#xff0c;从营销和库存管理到客户支持和数据分析。这些职责的复杂性可能是压倒性的&#xff0c;即使有一个专门的团队。 聊天机器人可以通过指导您的客户完成购买过程并回答他们有关产品的问题来提供更好的体验。例如SaleSmartly&#xff…

房地产推广传单制作攻略,打造让人惊艳的电子传单

随着互联网的发展&#xff0c;传统的纸质传单已经逐渐被电子版传单所取代。电子版传单不仅可以节省成本&#xff0c;还可以更好地展示房产信息。在传统的设计软件中制作电子版传单需要一定的门槛&#xff0c;但是现在有了乔拓云网的后台&#xff0c;设计电子版房产H5传单变得简…