Linux之进程间通信之管道

news/2024/11/30 11:29:39/

进程间通信的目的:

1、数据传输:一个进程需要将它的数据发售那个给另外一个进程。

2、资源共享:多个进程之间需要共享同样的资源。

3、通知事件:一个进程需要向另外一个或者一组进程发送消息,通知它们发生了某种事件(比如:进程终止时要通知父进程)。

4、进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时告知它的状态改变。

进程间通信的本质:

进程间通信的本质其实是:让不同的进程看到了同一份资源。

通过进程的学习我们知道进程之间是具有独立性的,各自进程的数据对方是看不到的,就算是父子进程随意他们的数据是共享的但一旦方式写入。就会发生写时拷贝,数据各自私有一份,所以了进程间进行通信是很困难的。 这也就意味着进程之间要想进行通信,一定要借助第三方资源。这个第三方资源不属于这些进行通信进程中的任何一个。有了这个第三方资源这些进程可以向这个资源里面写入数据或者读取数据,进而实现进程间通信。而这个第三方资源通常是OS提供的内存区域。因此我们可以得出结论:进程间通信的本质是让不同进程看到同一份资源。

一、前提条件(实现进程间通信)

1.进程是具有独立性的--无疑增加了通信的成本。

2.要让两个不同的进程,进行通信,前提条件是要看到同一份“资源。

3.任何进程的通信手段

a.想办法,先让不同的进程,看到同一份资源

b.让一方写入,一方读取,完成通信过程,至于,通信目的与后续工作,要结合具体场景。

二、匿名管道

1、管道的概念

管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。 例如:我们使用统计一个文件中代码的行数。

cat proc.cc | wc -l

其中cat指令和wc指令是两个程序当他们运行起来时就变成进程了cat通过标准输出将数据放到管道中wc再从管道中拿数据,至此就完成了进程间通信。

2、匿名管道的概念

匿名管道多用于具有血缘关系的进程进行通信,多用于父子进程。

我们在上面说进程间通信的本质是让不同的进程看到同一份资源,那么使用匿名管道也一定要让父子进程看到同一份资源。匿名管道其实是让父子进程看到了同一份被打开的文件资源,本质其实是一段内核缓冲区。然后了父子进程就可以对这个资源进行读写操作了,进而实现了进程间通信。

3、pipe函数

pipe函数是用于创建匿名管道,pipe函数原型如下:

int pipe(int pipefd[2]);

pipe函数的参数是一个输出型参数,数组pipefd是用来获取读端和写端的文件描述符。

pipe函数调用成功返回0失败返回-1。

4、匿名管道实现通信的原理

管道也是文件,站在管道文件的角度来理解管道实现通信的原理。

管道是一个文件,当一个进程以读和写的方式打开一个管道。再创建一个子进程,子进程会以父进程为模板,拷贝父进程的部分内容。此时file_strcut里的数组(文件描述符与文件的映射关系)会是父进程的拷贝。此时,父子进程都指向了管道文件(同一块空间)并且子进程也是以读写方式打开的该文件(因为子进程会继承父进程代码,父进程再创建子进程之前以读写方式打开的文件),如果将一个进程对文件进行写,一个进程对文件进行读,由于来给你进程指向同一空间,所以读进程拿到的数据就是写进程写进去的数据。此时就完成了对文件的通信。

5、匿名管道的使用代码

实现父进程去读取,子进程去写入的操作。

#include<iostream>
#include<cerrno>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
​
int main()
{int pipefd[2]={0};//1.创建管道int n=pipe(pipefd);if(n<0){std::cout<<"pipe error,"<<errno<<": "<<strerror(errno)<<std::endl;return 1;}std::cout<<"pipefd[0]:"<<pipefd[0]<<std::endl; //读端std::cout<<"pipefd[1]:"<<pipefd[1]<<std::endl; //写端//2.创建子进程pid_t id=fork();assert(id!=-1);//正常应该用判断,我这里直接断言;意料之外用if,意料之中用assert。
​if(id==0){ //子进程//3.关闭不需要的fd,让父进程去读取,子进程去写入close(pipefd[0]); //关闭读
​//4.开始通信--结合某种场景const std::string namestr="hello,我是子进程";int cnt=1;char buffer[1024];while(true){snprintf(buffer,sizeof buffer,"%s,计算器:%d,我的ID:%d\n",namestr.c_str(),cnt++,getpid());write(pipefd[1],buffer,strlen(buffer)); //不断写sleep(1);}
​close(pipefd[1]);exit(0);}//父进程//3.关闭不需要的fd,让父进程去读取,子进程去写入close(pipefd[1]);//4.开始通信char buffer[1024];while(true){sleep(10);int n=read(pipefd[0],buffer,sizeof(buffer)-1);if(n>0){buffer[n]='\0';std::cout<<"我是父进程,子进程给我信息:"<<buffer<<std::endl;}}close(pipefd[0]);return 0;
}

6、匿名管道的四种情况

6.1写进程比较慢时,读进程会进入阻塞状态,读进程只能等待
  • 当读进程进行读操作时,当读条件不满足,读进程进入阻塞状态。

读条件不满足:管道里没有数据或者说写端没有往管道写数据。

读进程进入阻塞状态:PCB的状态设置为S,该进程从运行队列进入等待队列,等待管道中有数据。

由于写进程比读进程慢,读进程在读时,大部分时间,管道是空的,此时读进程会进入阻塞状态,等待管道中有数据。

6.2当写进程进行写操作时,管道慢了,写进程就不能再写了

当写进程进行读操作时,当写条件不满足,写进程进入阻塞状态。写条件不满足:管道满了的时候

    写进程进入阻塞状态:PCB的状态设置为S,该进程从运行队列进入等待队列,等待管道中可以写入数据。

改变上面代码:子进程写数据没有时间限制,父进程读数据延时5s。

进程间同步的概念:一个进程快导致另一个进程也快,一个进程慢导致另一个进程也慢。一个进程受到控制,另外一个进程也受到控制,着就叫进程间同步。

6.3如果关闭写端文件描述符,读进程会一直读到文件结尾

这里说明,如果将写文件描述符关闭,读进程最终一定会读到管道的结尾。因为已经没有进程往文件中写入数据了。

6.4如果关闭读进程文件,写端一直写,写进程可能会被进程直接杀死,进程异常退出

读进程退出读文件描述符,系统传13号信号杀死写进程。并不是将写进程变成僵尸状态,上面是因为写进程是子进程,但是父进程没有退出。

所以一般先将写进程关闭写文件描述符,再关闭读进程的读文件描述符。

7、匿名管道的特征

三、命名管道

其实原理和匿名管道差不多,只是需要先创建一个命名管道再一个进程以读或者写的方式来打开该管道文件,再另外一个进程不需要创建管道,只需要以写或者读的方式来打开管道文件。再调用读写系统调用来往文件写或者读,来进行进程间通信。

两进程分别对同一管道文件分别用读或写的方式打开,两进程看到同一文件(资源)。不需要创建子进程,可以是两个不相关的进程。

1、创建命名管道

1.1、使用命令行mkfifo创建管道

1.2、使用函数创建管道

//头文件
#include <sys/types.h>
#include <sys/stat.h>
​
int mkfifo(const char *pathname,mode_t mode)//返回值:成功返回0,失败返回-1
//参数:filename 路径+文件名
//      mode:权限

创建命名管道代码:

 #include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>int main(){umask(0);//设置掩码为0int res=mkfifo("./fifo",0644);                          if(res==-1){perror("mkfifo error");exit(2);}return 0;}

2、使用命名管道实现两个进程间的通信代码实例

com.hpp: 相当于头文件
#pragma once
#include<iostream>
#include<string>
​
#define NUM 1024
using namespace std;
​
const string fifoname="./fifo";
uint32_t mode=0666;
server.cc: 服务端
#include<iostream>
#include<cerrno>
#include<cstring>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
​
#include "com.hpp"
​
using namespace std;
int main(){//创建管道文件,我们只需要创建一次umask(0); //这个设置并不影响系统的默认位置,只影响当前进程int n=mkfifo(fifoname.c_str(),mode);if(n!=0){cout<<errno<<":"<<strerror(errno)<<endl;return 1;}cout<<"创建管道文件成功"<<endl;//让服务端直接开启管道文件int rfd = open(fifoname.c_str(),O_RDONLY);if(rfd<0){cout<<errno<<":"<<strerror(errno)<<endl;return 2;}cout<<"成功打开管道文件,正常通信"<<endl;//3.正常通信char buffer[NUM];while(true){buffer[0]=0;ssize_t n=read(rfd,buffer,sizeof(buffer)-1);if(n>0){buffer[n]=0;//cout<<"客户端的信息# "<<endl;cout<<"客户端的信息# "<<buffer<<endl;//printf("%c",buffer[0]);fflush(stdout);}else if(n==0){cout<<"客户端退出,服务端也应该退出"<<endl;break;}//关闭不要的fdclose(rfd);unlink(fifoname.c_str());}
client.cc: 用户端
#include<iostream>
#include<cerrno>
#include<cstring>
#include<cassert>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
​
#include "com.hpp"
int main(){int wfd=open(fifoname.c_str(),O_WRONLY);if(wfd<0){cerr<<errno<<":"<<strerror(errno)<<endl;return 2;}//可以进行常规通信了char buffer[NUM];while(true){cout<<"请输入你的消息#";char *msg=fgets(buffer,sizeof(buffer),stdin);assert(msg);(void)msg;buffer[strlen(buffer)-1]=0;ssize_t n=write(wfd,buffer,strlen(buffer));assert(n>=0);(void)n;
​}close(wfd);return 0;
}

即可以实现在用户端输入数据,在服务端接收。


http://www.ppmy.cn/news/487516.html

相关文章

数据孤岛如何形成,企业如何破解?

国内企业数据化现状 在数字化时代&#xff0c;数据已经成为了企业不可或缺的重要资产。企业内部部门或系统之间存在着数据割裂现象&#xff0c;导致数据无法流通和共享&#xff0c;从而形成数据孤岛的现象。对于企业来说&#xff0c;数据孤岛问题是十分普遍的&#xff0c;它阻…

数据库系统概述——第七章 数据库设计(知识点复习+练习题)

&#x1f31f;博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;离散数学考前复习&#xff08;知识点题&#xff09; &#x1f353;专栏&#xff1a;概率论期末速成&#xff08;一套卷&#xff09; &#x1f433;专栏&#xff1a;数字电路考前复习 &#x1f99a;专栏&am…

JavaScript实现简单图片滚动 --9张图告诉你,C罗欲哭无泪

源代码下载&#xff1a;http://download.csdn.net/detail/u011043843/7510425 昨晚德国和葡萄牙的焦点之战你看了吗&#xff1f;北京时间凌晨的比赛中。C罗领衔的葡萄牙0-4德国被完灭……他是金球奖得主、欧洲金靴、欧冠冠军核心。在葡萄牙队……9张图 C罗告诉你什么叫欲哭无泪…

c罗图片带字经典语言,20条经典的唯美的图片带字-感人的情话

20条经典的唯美的图片带字-感人的情话以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01; 一、一辈子是场修行。短的是旅途&#xff0c;长的是人生。旅行&#xff0c;能让你遇到那个更好的自己。…

c罗讲什么语言教学,C罗来中国啦!15万小费算什么,他的语言天赋才是我羡慕的!...

原标题&#xff1a;C罗来中国啦&#xff01;15万小费算什么&#xff0c;他的语言天赋才是我羡慕的&#xff01; 昨天C罗的球迷沸腾了&#xff0c;因为他来北京了&#xff01;19日早晨&#xff0c;葡萄牙球星C罗抵达北京&#xff0c;开启了他的中国行。这是他加盟意甲尤文图斯队…

c罗图片带字经典语言,c罗励志语录 c罗经典语录名言

简介c罗励志语录 c罗经典语录名言 1.记得我以前说过&#xff0c;我是高富帅这样的话&#xff0c;其实那是一个错误。人都犯反错误&#xff0c;但重要的是&#xff0c;你一定要认识自己的错误&#xff0c;要勇于改正&#xff0c;我说那话的时候是在一场比赛之后&#xff0c;那场…

c罗图片带字经典语言,c罗足球名言短句 c罗的那些霸气名言

1、街上的孩子们都比我大&#xff0c;我不得不不停地摇晃他们&#xff0c;当然他们经常把我推倒或推倒。这是一个精神上的挑战。 2、我比梅西更好&#xff0c;我不能把法拉利和保时捷相提并论。 3、你的爱让我坚强&#xff0c;你的恨让我势不可挡。 4、你的爱让我坚强&#xff…

Godot 4 源码分析 - Project Manager

简单来说&#xff0c;Godot 4一共有三种运行模式&#xff1a;工程管理、编辑、运行 有点意思的是&#xff0c;每次调试&#xff0c;只能在其中一种模式下运行 如果同时配置了编辑器与工程管理器&#xff0c;则会报错&#xff1a; if (editor && project_manager) {O…