首页 > 其他分享 >无名管道和命名管道

无名管道和命名管道

时间:2023-03-02 23:11:33浏览次数:38  
标签:阻塞 无名 进程 管道 fd 关闭 命名 读端

管道的实质:内核中的一块缓冲区

 

管道是单工的,数据只能从一个方向流向另外一个方向(单向);想要双向通信时,需要建立两个管道。

先写进管道中的数据先被读出。

 

无名管道:

  用于有血缘关系的进程

  int pipe(int fd[2])

  返回:成功返回0;失败:-1

 

 

 因为pipe函数在fork之前调用,所以只在内核中创建了一个管道,但是文件描述符却被复制了一份;

当父进程要写时,必须先关闭读端fd[0],在往写端fd[1]里面写,写完再关闭写端;子进程就要先关闭写端fd[1],在从读端fd[0]中读取,读完再关闭读端。=====》单工

//一个进程往管道里写,另一个进程从管道中读
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <sys/wait.h> char *cmd1[] = {"cat","/etc/passwd",NULL}; char *cmd2[] = {"grep","root",NULL}; int main(void) { pid_t pid; int fd[2]; if(pipe(fd) < 0){ printf("pipe failed!!\n "); exit(0); } for(int i = 0;i < 2;i++){ pid = fork(); if(pid < 0){ printf("fork failed!!!\n"); exit(0); }else if(pid == 0){//child process if(i == 0){ //first child 往管道里面写 //先关闭读端 close(fd[0]); //cat命令时输出到调准输出上的,所以要将输出重定向到管道的写端 if(dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO){//标准输出现在是指向fd[1] printf("dup2 failed !!!\n"); exit(0); } close(fd[1]); if(execvp(cmd1[0],cmd1) < 0){ printf("execvp error!!!\n"); exit(1); } break; } if(i == 1){//second child 从管道里面读 //写关闭写端 close(fd[1]); //grep命令是从标准输入读取,我们到从管道中读取,所以要将标准输入重定向到管道的读端 if(dup2(fd[0],STDIN_FILENO) != STDIN_FILENO){//标准输出现在是指向fd[1] printf("dup2 error !!!\n"); exit(0); } close(fd[0]); if(execvp(cmd2[0],cmd2) < 0){ perror("error:"); exit(1); } break; } }else{//parent process if(1 == i){ close(fd[0]); close(fd[1]); wait(NULL); wait(NULL); } } } return 0; }

管道是阻塞性的,若管道中没有数据,读取管道的那个进程将阻塞;

当一个进程不断往管道里面写数据并且没有进程从管道中读数据,只要管道没有装满就可以,一旦装满了就会报错。====》管道中的数据读了就没有了

 

不完整管道:

  当读一个写端已被关闭的管道(父子进程都将fd[1]关闭了),当把管道中的数据读完后,read会返回0

  当写一个读端已被关闭的管道(父子进程都将fd[0]关闭了),会产生一个SIGPIPE信号,写的那个进程可以忽略或捕捉这个信号。同时这个进程中的errorno被设置为EPIPE

 

标准库中管道的操作:

  

 

  popen函数和system函数类似;

   popen函数的内部实现原理:

  

 

 命名管道:

  int mkfifo(const char *pethname ,mode_t mode)

  可以在两个没有任何关系的进程间通信;

  命名管道本质也是内核中的一块缓存,但是他又在文件系统中以一个特俗的设备文件(管道文件)存在。=====>命名管道

  在文件系统中只有一个索引块(i节点)存放文件的路径,没有数据块,所有数据是存放在内核中的;

  命名管道读和写必须同时打开(即以读打开管道的进程和以写打开的进程都要运行),否则单独读或单独写会引起进程阻塞(即只有一个进程在运行就会阻塞)

 

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

  相同点:

    都是阻塞性的读写;

    都是用与socket的网络通信

    阻塞不完整管道(有一端关闭):

      当读一个写端已被关闭的管道(父子进程都将fd[1]关闭了),当把管道中的数据读完后,read会返回0

      当写一个读端已被关闭的管道(父子进程都将fd[0]关闭了),会产生一个SIGPIPE信号,写的那个进程可以忽略或捕捉这个信号。同时这个进程中的errorno被设置为EPIPE 

    阻塞完整管道(两端都开启):

      读时,要么阻塞,要么读到数据

      写时,写满管道出错

    非阻塞不完整管道(有一端关闭):

      单纯读时直接报错;

      当写一个读端已被关闭的管道(父子进程都将fd[0]关闭了),会产生一个SIGPIPE信号,写的那个进程可以忽略或捕捉这个信号。同时这个进程中的errorno被设置为EPIPE

    非阻塞完整管道(两端都开启):

      读时,直接报错;

      写时,写满管道出错

  不同点:

     打开方式不一样;

    pipe通过fcntl系统调用设置O_NONBLOCK来设置非阻塞读写;

    FIFO可以通过fcntl或open来设置非阻塞;

标签:阻塞,无名,进程,管道,fd,关闭,命名,读端
From: https://www.cnblogs.com/zj-studyrecoding/p/17173963.html

相关文章

  • 命名的字符支持
    文件名不适合用:/\|:;*?"<>-=$.#&()[]{}!`~文件名可以用:_+,@% nodejs对象keyvalue支持utf-8,base64肯定支持nodejs变量命名字符有限 url虚拟路径path可以自......
  • linux 网络命名空间
    #创建网络命名空间ipnetnsaddnetns1#查看新增的网络命名空间ipnetnslist#查看挂载点ls/var/run/netns/#进入网络命名空间查看ipnetnsexecnetns1ip......
  • TypeScript 命名空间
    TypeScript命名空间命名空间一个最明确的目的就是解决重名问题。假设这样一种情况,当一个班上有两个名叫小明的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些......
  • mybatisPlus驼峰命名映射
    踩坑记录项目使用mybatisPlus,在查询时候,数据库明明有值,且可返回,但是到了list里部分值就是null。最后发现是封装的实体中的字段与数据库写的一样,如数据库是user_name,实体......
  • bash -s和管道符传参问题
      第二个命令后面如果加--mirrorAliyun会报错,所以查看了文档  其他的使用标准输出的方式还有xargs和连字符(减号)"-",这两个参数的方式,后面加--mirrorAliyun也没......
  • 变量的命名规范
    所有变量、方法、类名:见名知意类方法变量:首字母小写和驼峰原则:monthSalary除了第一个字母以外,后面单词首字母大写局部变量:首字母小写和驼峰原则常量:大写字母和下划线:MA......
  • 用bat,cmd批处理命令创建新文件和文件夹(含删除复制重命名)
     用bat,cmd批处理命令创建新文件和文件夹(含删除复制重命名) 一、用CMD创建和删除新文件夹主要CMD命令:MD [盘符:\][路径\]<文件夹名>  //创建新文件夹(mkd......
  • Java数据类型,变量命名的标准 (AJCG),分支和循环,文档注释的要求
    Java数据类型,变量,分支和循环Java中的八大基本数据类型数据类型占用字节数数据范围byte1B-128~127short2B-32768~32767int4B-2^31~2^31-1......
  • Python基础篇-变量名命名规则
    Python变量名命名规则遵循PEP8原则:普通变量:max_value全局变量:MAX_VALUE内部变量:_local_var和关键字重名:class_函数名:bar_function类名:FooClass布尔......
  • Python中的命名规范
    变量命名准则您应当尽量使自己的变量命名含义清晰,不要使用混乱的字母、数字、表情等意义不明的字符来命名变量一般来说,您不应当使自己的风格频发变换——如果可能,请将整......