ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

管道pipe/fifo

2021-02-17 14:03:28  阅读:172  来源: 互联网

标签:int fifo pipe 管道 fd ret exit include


1.管道的概念

  管道本质上是内核中的一个缓冲区,让具有血缘关系的进程之间可以进行通信。它其实相当于一个伪文件,不占用磁盘空间,我们可以通过和对文件一样的读写方式去操作管道。

  管道具有两部分,读端和写端,分别对应两个文件描述符,数据从写端流入,从读端流出。

  操作管道的进程被销毁之后,管道会被系统自动释放。

  管道读写的时候默认是阻塞的。

   

2.管道的原理

  管道的内部是通过循环队列实现的,先进先出。

  管道的大小即缓冲区的大小默认是4k,但会根据实际情况做适当调整。

 

3.管道的局限性

  由于管道的实现形式是队列,使用数据只能读取一次,不能重复读取。

  管道实现形式是半双工的,所以在一端写数据的时候,另一段只能读数据,不能写数据。

  匿名管道pipe只适合于有血缘关系的进程使用。

 

4.创建匿名管道

int pipe(int fd[2]);

  fd:传出参数

  fd[0]:读端

  fd[1]:写端

 

5.进程之间使用管道通信

  单个进程可以使用管道完成读写操作。

  一个进程在读数据的时候要关闭写端,同理,在写数据的时候要关闭读端。

例:父子进程间通信,实现ps aux | grep bash

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <fcntl.h>
 5 
 6 int main()
 7 {
 8         int fd[2];
 9         int ret = pipe(fd);
10         if(ret == -1){
11                 perror("pipe error:");
12                 exit(-1);
13         }
14 
15         pid_t pid = fork();
16         if(pid == -1){
17                 perror("fork error:");
18                 exit(-1);
19         }else if(pid > 0){
20                 close(fd[0]);
21                 dup2(fd[1],STDOUT_FILENO);
22                 execlp("ps","ps","aux",NULL);
23                 perror("execlp error:");
24                 exit(-1);
25         }else{
26                 close(fd[1]);
27                 dup2(fd[0],STDIN_FILENO);
28                 execlp("grep","grep","--color=auto","bash",NULL);
29                 perror("execlp error:");
30                 exit(-1);
31         }
32         return 0;
33 }

 

兄弟进程间通信,实现ps aux | grep bash

 1        int fd[2];
 2         int ret = pipe(fd);
 3         if(ret == -1){
 4                 perror("pipe error:");
 5                 exit(-1);
 6         }
 7 
 8         int i;
 9         int n = 2;
10         pid_t pid;
11         for(i=0;i<n;i++){
12                 pid = fork();
13                 if(pid == 0){
14                         break;
15                 }
16         }
17 
18         if(i == 0){
19                 close(fd[0]);
20                 dup2(fd[1],STDOUT_FILENO);
21                 execlp("ps","ps","aux",NULL);
22                 perror("execlp error:");
23                 exit(-1);
24         }else if(i == 1){
25                 close(fd[1]);
26                 dup2(fd[0],STDIN_FILENO);
27                 execlp("grep","grep","--color=auto","bash",NULL);
28                 perror("execlp error:");
29                 exit(-1);
30         }else{
31                 pid_t wpid;
32                 close(fd[0]);
33                 close(fd[1]);
34                 while((wpid = wait(NULL))!=-1){
35                         printf("child = %d\n",wpid);
36                 }
37                 printf("child are all died\n");
38         }
39         return 0;
40 }

 

6.管道的读写操作

读操作:

  有数据时:read(fd)正常读,返回读出的字节数。

  无数据时:①写端全部关闭,read接触阻塞,返回0(相当于读文件读到了尾部)

       ②没有全部关闭,read阻塞

写操作:

  读端全部关闭:写的内容超出缓冲区大小时,管道破裂,内核给当前进程发信号SIGPIPE,进程被终止。

  读端没有全部关闭:①缓冲区写满了:write阻塞

           ②缓冲区没有写满:write继续写

 

设置管道为非阻塞

  管道默认两端都为阻塞,由于fcntl函数可以修改文件属性,所以可通过fcntl函数设置管道为非阻塞。如设置读端为非阻塞:

设置方法:

  获取原来的flags:int flags = fcntl(fd[0],F_GETFL);

  设置新的flags:flags |= O_NONBLOCK;

         fcntl(fd[0],F_SETFL,flags);

7.查看管道缓冲区大小

命令:ulimit -a

函数:fpathconf

 

8.有名管道fifo

特点:

  ①有文件名

  ②在磁盘上有这样一个文件(通过ls -l查看  ->  p)

  ③伪文件,大小为0

  ④在内核中有一个对应的缓冲区

  ⑤半双工的通信方式

使用场景:

  没有血缘关系的进程间通信。

创建方式:

  命令:mkfifo 管道名

  函数:mkfifo

操作方式:与文件大致相同

  open/close

  read/write

  不能执行lseek操作

进程间通信:

读端:

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/stat.h>
 7 
 8 int main(int argc,char *argv[])
 9 {
10         if(argc < 2){
11                 printf("./a.out filename\n");
12                 exit(-1);
13         }
14 
15         int ret;
16         ret = access(argv[1],F_OK);
17         if(ret == -1){
18                 int r = mkfifo(argv[1],0664);
19                 if(r == -1){
20                         perror("mkfifo error:");
21                         exit(-1);
22                 }
23         }
24 
25         int fd = open(argv[1],O_RDONLY);
26         if(fd == -1){
27                 perror("open error:");
28                 exit(-1);
29         }
30         char buf[128];
31         while(1){
32                 ret = read(fd,buf,sizeof(buf));
33                 buf[ret] = 0;
34                 printf("%s\n",buf);
35         }
36         close(fd);
37         return 0;
38 }

 

写端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <string.h>
 6 #include <sys/types.h>
 7 #include <sys/stat.h>
 8 
 9 int main(int argc,char *argv[])
10 {
11         if(argc < 2){
12                 printf("./a.out filename\n");
13                 exit(-1);
14         }
15 
16         int ret;
17         ret = access(argv[1],F_OK);
18         if(ret == -1){
19                 int r = mkfifo(argv[1],0664);
20                 if(r == -1){
21                         perror("mkfifo error:");
22                         exit(-1);
23                 }
24         }
25         int fd = open(argv[1],O_WRONLY);
26         if(fd == -1){
27                 perror("open error:");
28                 exit(-1);
29         }
30 
31         char *buf = "hello,world";
32         while(1){
33                 sleep(1);
34                 ret = write(fd,buf,strlen(buf)+1);
35         }
36         close(fd);
37         return 0;
38 }

 

标签:int,fifo,pipe,管道,fd,ret,exit,include
来源: https://www.cnblogs.com/czhdbk/p/14407996.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有