【Linux】管道

什么是管道?—–我们把从一个进程连接到另一个进程的一个数据流成为管道。
作用:使进程间相互通信。
这里写图片描述

管道分为两种:1、匿名管道;2、命名管道

匿名管道
创建一个匿名管道——函数原型:int pipe(int fd[2]);
参数:fd是文件描述符组,fd[0]表示读端,fd[1]表示写端。(0像读东西的嘴,1像写字的笔)。
返回值:创建成功返回0;失败返回错误代码。
写一个测试用例:

  1#include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<unistd.h>
  5 //从键盘读取数据额,写入数据到管道,从管道读取数据,写到屏幕
  6 int main()
  7 {                                                                                                                                               
  8     int fds[2];
  9     int p = pipe(fds);
 10     if(p<0){
 11         perror("pipe failded");
 12         exit(1);
 13     }    
 14     printf("pipe ok\n");
 15     //从标准输入读数据
 16     while(1){
 17         char buff[1024] = {0};
 18         ssize_t read_size = read(0,buff,sizeof(buff)-1);
 19         if(read_size<0){
 20             perror("read failed");
 21             return 122        }    
 23         if(read_size==0){
 24             //读到EOF
 25             printf("read done\n");
 26             return 0;
 27         }    
 28         buff[read_size] = '\0';
 29         //写入管道
 30         write(fds[1],buff,strlen(buff));
 31         //从管道读数据
 32         char out_buff[1024] ={0};
 33        ssize_t reads = read(fds[0],out_buff,sizeof(out_buff)-1);
 34         if(reads<0)                                                                                                                             
 35         {    
 36             perror("read pipe failded");
 37             return 1;
 38         }    
 39         out_buff[reads] = '\0';
 40         //写到标准输出上
 41         write(1,out_buff,strlen(out_buff));
 42     }       
 43     return 0;
 44 }                     

结果:
这里写图片描述

我们在实现一个父子进程间利用管道通信的例子:
这里写图片描述
fork之前父子进程都可从管道读和写;fork之后子进程只能写(或者读),父进程只能读(或者写)。
代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5        
  6 int main()
  7 {      
  8     int fds[2];
  9     int ret = pipe(fds);
 10     if(ret<0){
 11         perror("pipe");
 12         return 1;
 13     }  
 14     pid_t pid = fork();
 15     if(pid>0){                                                                                                                                                                             
 16         //father
 17         //从管道中读
 18         char buff[20] = {0};
 19         close(fds[1]);//父进程关闭写端
 20         ssize_t read_size = read(fds[0],buff,sizeof(buff)-1);
 21         if(read_size<0){
 22             perror("read faild");
 23             return 1;
 24         }
 25         if(read_size==0){
 26             printf("read done\n");
 27             return 0;
 28         }
 29         buff[read_size] = '\0';
 30         //写到标准输出
 31        printf("%s\n",buff);
 32     }else if(pid==0){
 33         //child
 34      i   close(fds[0]);//子进程关闭i
 35         write(fds[1],"hello word",10);
 36         close(fds[1]);
 37         exit(0);
 38     } 
 39     return 0;
 40 }    

结果:
这里写图片描述

匿名管道读写规则:
阻塞方式:
1. 1、(若管道数据已空)调用read阻塞,直到有进程往里写数据
2. 2、(管道满)调用write阻塞,直到有进程读数据。
非阻塞方式:
3. 1、(管道数据已空)调用read返回-1;errno值为EAGAIN
4. 2、(管道满)调用write返回-1;errno值为EAGAIN
匿名管道的特点:
1. 用于有亲缘关系的进程;通常,一个管道有一个进程创建,然后由该进程调用fork,此后父、子进程之间就可用该管道。
2. 面向字节流
3. 生命周期随进程,进程退出,管道则释放。
4. 匿名管道半双工,数据只能向一个方向流动,若需要双方通信,需要建立两个管道。
5. 内核对管道操作进行同步与互斥。

命名管道
创建一个命名管道:
1、从命令行上创建mkfifo filename
这里写图片描述
2、从程序创建:相关函数:int mkfifo (const char *filename,mode_t mode)
命名管道和匿名管道的区别:

  1. 创建匿名管道—-pipe函数;创建命名管道—mkfifo函数,打开用open
  2. 匿名管道只能用于具有亲缘关系的进程;命名管道可用于任意多个进程。
  3. 其余与匿名管道相同。

命名管道读写规则:

  1. (阻塞方式)若以‘r’方式打开一个命名管道时,它会阻塞在open函数中,直到有进程以‘w’方式打开;(反过来也是如此)
  2. 写端关闭时,读端立刻返回0;
  3. (非阻塞方式)如果以一个非阻塞‘r’方式打开,open函数立即返回;当在尝试读时,read返回0,当另一个进程以‘w’方式打开,read返回-1,虽然已‘w’方式打开,但是并未写数据;
  4. 如果以一个非阻塞‘w’方式打开,则打开失败。

    例:用命名管道实现server&client通信:
    1、创建一个命名管道myfifo;
    这里写图片描述
    2、实现server
    这里写图片描述
    3、实现client
    这里写图片描述
    结果:
    这里写图片描述

    扫描二维码关注公众号,回复: 1214323 查看本文章

猜你喜欢

转载自blog.csdn.net/prefect_boy/article/details/78875736