【Linux系列】进程间通信方式-管道详解

进程间通信(一)

简而言之就是操作系统为上层提供的进程间通信的方式
为什么要操作系统提供呢?
每个进程具有独立性,每个进程访问的都是自己的虚拟地址空间的虚拟地址
因此需要操作系统提供一个进程间都可访问的区域来实现通信
因为应用场景不同,因此提供的方式也多种多样


管道

管道 :用于实现进程间的数据传输功能
本质就是内核中的一块缓冲区

管道的种类 :匿名管道和命名管道

1. 匿名管道


概念:在内核中申请一块固定大小的缓冲区,程序拥有写入和读取的权利,一般使用fork函数实现父子进程的通信。
(1)在内核中创建管道

#include <unistd.h>
 int pipe(int pipefd[2]);    // 返回值:若成功返回0,失败返回-1

(2)创建成功则返回管道的操作句柄
(3)操作方式类似于文件操作

父进程创建管道,得到两个⽂件描述符指向管道的两端
父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。

(4)pipefd[0] pipefd[1] 对应两个操作句柄,一个用于读取数据,一个用于写入数据

父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。

2.管道的特性

管道是半双工通信
管道自带同步与互斥

互斥:写操作不超过PIPE_BUF大小(4096字节),保证原子性,保证安全操作
同步:管道中没有数据,read会堵塞,缓冲区满,write会堵塞

管道提供字节流服务:有序的(先进先出),可靠的,不限制传输大小,基于连接的

若所有读端关闭,则写入异常,导致进程退出
若所有写端关闭,则读完数据不会阻塞,返回0

管道的生命周期随进程,进程关闭则释放

管道符 : |

连接两个命令,把前面命令的输出结果交给后面的命令处理

ps -ef | grep ssh
ps进程和ssh进程通过匿名管道进行数据传输

实现原理:

创建管道和两个子进程,ps输出到标准输出(1),grep从标准输入(0)拿数据,只需要把1重定向到管道的写,把0重定向到管道的读,这时候写入的数据写道管道里,读数据就从管道读数据

上代码

   #include <stdio.h>
   #include <unistd.h>
   #include <stdlib.h>
   #include <string.h>
   #include <sys/wait.h>
   
   int main (int argc, char *argv[])
   {
       int pipefd[2];
       if (pipe(pipefd) < 0) {
          perror("pipe error");
          return -1;
      }
      pid_t ps_pid = fork();
      if (ps_pid == 0) {
          close(pipefd[0]);
          dup2(pipefd[1], 1);
          execlp("ps", "ps", "-ef", NULL);
          exit(0);
      }
      pid_t grep_pid = fork();
      if (grep_pid == 0) {
          close(pipefd[1]);
          dup2(pipefd[0], 0);
          execlp("grep", "grep", "ssh", NULL);
          exit(0);
      }
      close(pipefd[0]);
      close(pipefd[1]);
      waitpid(ps_pid, NULL, 0);
      waitpid(grep_pid, NULL, 0);
      return 0;
  }
3.命名管道

内核中的缓存区具有标识符,可用于主机上的任意进程间通信
本质上还是缓存区,只是标识符是可见于文件系统的管道文件
缓冲区大小和磁盘空间无关

 	int ret = mkfifo("./test.fifo", 0664);
    if (ret < 0 && errno != EEXIST) {
          perror("mkfifo error");
          return -1; }
    printf("create fifo success!\n");

如果文件已经存在,我们不关注这个错误继续执行
注意此处需要给定权限
返回值:成功返回0,失败返回-1

    int fd = open("./test.fifo", O_RDONLY); //以只读方式打开
    if (fd < 0) {
        perror("open error");
        return -1; 
    } 
    printf("open success!!\n");
    int fd = open("./test.fifo", O_WRONLY); //以只写方式打开
    if (fd < 0) {
        perror("open error");
        return -1; 
    }   
    printf("open success!!\n");
4.命名管道的特性

如果命名管道没有被写的方式打开,则只读打开 就会阻塞
如果命名管道没有被读的方式打开,则只写打开 就会阻塞

谢谢大家观看,更多代码请点击下方地址,进入我的的github

//lieng-github

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值