> 文章列表 > 【Linux】进程间通信之管道(pipe)

【Linux】进程间通信之管道(pipe)

【Linux】进程间通信之管道(pipe)

文章目录

  • 前言
  • 为什么要进程通信
  • 进程间通信的理论依据
  • 管道
  • 管道的原理
  • 创建匿名管道
  • 管道的特点
  • 管道的场景
  • 利用管道控制子进程
  • 命名管道
  • 命名管道的打开规则
  • 命名管道和匿名管道的区别
  • 用命名管道实现server和client通信

前言

大家好久不见,今天开始我们将进入进程间通信章节的学习。

为什么要进程间通信

现在看来,无非是为了资源共享。

进程间通信的理论依据

我们知道进程是独立的,如果我们要进行通信,前提是让两个进程能看到同一份资源。

管道

管道是unix中古老的通信方式,通过管道,我们可以完成进程间通信。
我们把从一个进程连接到另一个进程的数据流称之为管道。

管道的原理

父进程fork的时候,子进程会继承父进程打开的文件描述符,利用这个特性,设计出管道来完成进程间通信。
【Linux】进程间通信之管道(pipe)
即让父进程创建管道,并fork创建子进程,再关闭对应写/读端

创建匿名管道

#include <unistd.h>int pipe(int fd[2]);
功能:创建匿名管道
参数:fd,文件描述符数组,输出型参数,fd[0]读,fd[1]写
返回值:成功返回0,失败返回错误代码

管道的演示代码:

#include <iostream>
#include <string>
#include <cerrno>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <unistd.h>using namespace std;int main()
{//1.创建管道int pipeid[2];int n = pipe(pipeid);if(n < 0){cout << errno << strerror(errno) << endl;}cout << pipeid[0] << endl; //0是张嘴 就是读cout << pipeid[1] << endl; //1是个笔 就是写//2.创建子进程pid_t id = fork();assert(id != -1);if(id == 0){//3.关闭不需要的fd,父进程读取,子进程写close(pipeid[0]);//5.通信开始const string namestr = "hello,i am child";int cnt = 1;char buffer[1024];while(true){snprintf(buffer,sizeof(buffer),"%s,my cnt = %d,myPID = %d\\n",namestr.c_str(),cnt++,getpid());write(pipeid[1],buffer,strlen(buffer));sleep(1);}close(pipeid[1]);//让下面的代码被父进程独享exit(0);}//4.父进程关闭写close(pipeid[1]);//5.开始父子进程通信:要结合某种场景!!!!char buffer[1024];while(true){int n = read(pipeid[0],buffer,sizeof(buffer)-1);//这里-1是给 \\0 留位置cout << "没有被阻塞住" << endl;//cout << n << endl;if(n > 0){buffer[n] = '\\0';cout << "child send me message:" << buffer << endl;}}return 0;
}

管道的特点

1、单向通信,管道是半双工的特殊情况。半双工即上课模式,老师讲完,学生问问题。
2、管道本质是文件,有对应的文件描述符fd,因此管道的生命周期随进程。
3、管道通信通常在有血缘关系的进程间通信,如父子进程。
4、管道通信写入和读取次数不是严格匹配的,两者没有强相关。原因在于 字节流
5、具有一定协同能力,让读和写能按照一定步骤进行通信。自带同步机制

管道的场景

1、如果read读取了所有的管道数据,对方不发,只能等待
2、管道写满后不可以再写,因为管道是有大小的
3、如果write关闭,读完管道数据,再读就会返回0,表明读到文件的结尾
4、写端一直写,读端关闭,OS会杀死一直写入却不读的进程,13)SIGPIPE

利用管道控制子进程

管道不只可以用来进程间通信,也可以利用管道控制子进程,比如父进程发送指令使得子进程退出。

命名管道

上述由继承得到的管道关系被称为匿名管道,匿名管道只能在具有亲缘关系的进程间进行通信,假如我们想让两个毫不相关的进程通信,可以使用命名管道。

1、在命令行上创建一个管道
mkfifo [filename]2、函数调用
int mkfifo(const char* filename, mode_t mode)
参数:filename文件名,mode是开启管道的权限
返回值:调用成功返回0,调用失败返回-13、删除一个管道
unlink [filename]

命名管道的打开规则

  • 如果当前操作为读
    • 阻塞直到有相应进程写操作打开FIFO
    • 若设置O_NONBLOCK,立即返回成功
  • 如果当前操作为写
    • 阻塞直到有相应进程读操作打开FIFO
    • 若设置O_NONBLOCK,立即返回失败

命名管道和匿名管道的区别

1、命名管道由mkfifo创建,open开启。
2、匿名管道由pipe打开。

用命名管道实现server和client通信

server.cc

#include <iostream>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#include "comm.hpp"int main()
{//1、创建管道文件umask(0);int n = mkfifo(fifoname.c_str(),mode);if(n != 0){std::cout << errno << ":" << strerror(errno) << std::endl;return -1;}std::cout << "管道创建完成" << std::endl;//2、服务端开启管道文件int r_fd = open(fifoname.c_str(),O_RDONLY);if(r_fd < 0){std::cout << errno << ":" << strerror(errno) << std::endl;return -2;}std::cout << "管道文件已经成功开启,等待通信" << std::endl;//3、正常进行通信:char buffer[NUM];while(true){buffer[0] = '\\0';ssize_t n = read(r_fd,buffer,sizeof(buffer));//系统调用都不去管C语言字符串的规定//std::cout << n << std::endl;if(n > 0){buffer[n] = 0;std::cout << "clien:" << buffer << std::endl;}else if(n == 0){std::cout << "client quit, me quit too!" << std::endl;break;}else {std::cout << errno << ":" << strerror(errno) << std::endl;break;}}// 关闭close(r_fd);unlink(fifoname.c_str());return 0;
}

client.cc

#include <iostream>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#include "comm.hpp"int main()
{//以写方式打开管道int w_fd = open(fifoname.c_str(),O_WRONLY);if(w_fd < 0){std::cout << errno << ":" << strerror(errno) << std::endl;}//进行通信char buffer[NUM];while(true){std::cout << "请输入消息#";char* msg = fgets(buffer,sizeof(buffer),stdin);assert(msg);(void)msg;//1 2 3 4 5 /n/0//0 1 2 3 4 5 /0buffer[strlen(buffer)-1] = 0;if(strcasecmp(buffer,"quit") == 0) break;ssize_t n = write(w_fd,buffer,sizeof(buffer)-1);}return 0;
}

运行即可达到如下效果:
【Linux】进程间通信之管道(pipe)