linux系统编程-管道

管道的概念

  • 管道是一种最基本的IPC(进程间通信)机制,作用于有缘关系的进程间,调用pipe() 即可创建一个管道。它有如下特质:

  1. 本质是一个伪文件(实为内核缓冲区)
  2. 由两个文件描述符引用,一个表示读,一个表示写
  3. 规定数据从管道的写端流入管道,读端流出管道

  • 管道原理:内核使用环形队列,借助内核缓冲区(默认4K,可以使用ulimit –a 命令来查看)实现。
  • 管道的局限性:

  1.数据不能自己读,再自己写
  2. 数据一旦被读走,便不存在,不可反复读取
  3. 采用半双工通信,数据同时只能一个方向流动
  4. 只能在有血缘关系的进程间通信



pipe()函数

  • 函数原型:int pipe(int pipe[2]);  成功:0   失败:-1 设置error
  • 函数调用成功返回两个文件描述符,r ,w;不需要open,但是需要close。规定:
    fd[0]->r
    fd[1]->w
    记忆:读写 对应01



在这里插入图片描述

代码

  • 父进程创建管道,创建子进程,父进程写hello world进 pipe,子进程从pipe中读出来,再打印到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


 int main(void)
  {
   
          pid_t pid;
          int fd[2];
  
          char buf[512];
          int tem=pipe(fd);   //创建管道
          if(tem==-1)
          {
                  perror("pipe error");
                  exit(1);
          }
  
          pid = fork();    //创建子进程
          {
                  if (pid <0)
                  {
                          perror("fork error");
                          exit(1);
                  }
                  else if(pid == 0) //子进程
                  {
                          close(fd[1]);//关闭pipe的写端
                         int num=read(fd[0],buf,512);
                         if(num == 0)
                          {
                                  printf("gg\n");
                          }
                          printf("%s\n",buf);
                  }
                   else//父进程
                  {
                          close(fd[0]);  //关闭pipe的读端
                          write(fd[1],"hello world",sizeof("hello world"));
  
                  }
          }
  
          return 0;
  } 
  • 使用管道实现父子进程间通信,完成:ls | wc –l。假定父进程实现ls,子进程实现wc。ls命令正常会将结果集写出到stdout,但现在会写入管道的写端;wc –应该从stdin读取数据,但此时会从管道的读端读。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
   int main(void)
  {
          pid_t pid;
          int fd[2];
  
          pipe(fd);
          pid = fork();
  
          if(pid < 0)
          {
                  perror("fork error");
                  exit(1);
          } 
          else if(pid == 0) //子进程
          {
                  dup2(fd[0],0);   //将管道读端复制到 标准输入
                  close(fd[1]);    //关闭写端
                  execlp("wc","wc","-l",NULL);
          }
         else //父进程
         {
                 dup2(fd[1],1); //将管道的写端  复制到 表准输出
                 close(fd[0]); //关闭读端
                 execlp("ls","ls",NULL);
         }
         return 0;

 }

结果:输出当前目录 ls 列出的文件的个数

  • 使用管道实现兄弟进程间通信。 兄:ls 弟: wc -l 父:等待回收子进程。
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/wait.h>

 int main(void)
 {
         pid_t pid;
         int fd[2], i;
 
         pipe(fd);
  
         for (i = 0; i < 2; i++)
        {
                 pid=fork();
                 if(pid == 0)
                 {
                         break;
                }
         }
 
         if (i == 0)//子1
         {                     
                 dup2(fd[1], STDOUT_FILENO);            //复制 pipe写端 到 标准输出
                 close(fd[1]);
                 close(fd[0]);                           //关闭读写端
                 execlp("ls", "ls", NULL);
         }
         else if (i == 1)//子2
         {      
                 dup2(fd[0], STDIN_FILENO);          //复制 pipe读端 到 标准输入
                 close(fd[1]);                           //关闭读 写端
                 close(fd[0]);
                 execlp("wc", "wc", "-l", NULL);
         } else
         {
                 close(fd[1]);
                 close(fd[0]);
         
                 while(wait(NULL)>0);    //两个儿子wait两次
         }
         return 0;
 }

结果:列出当前目录的文件个数

猜你喜欢

转载自blog.csdn.net/zzyczzyc/article/details/82974685