管道通信(上)

管道通信(上)

(一)概述

  Linux Shell 都允许重定向,而重定向使用的就是管道。例如,ps | grep vsftpd 。管道是单向的、先进先出的、无结构的、固定大小的字节流。管道是Linux由Unix那里继承过来的进程间的通信机制,它是Unix早期的一个重要通信机制。其思想是,在内存中创建一个共享文件,从而使通信双方利用这个共享文件来传递信息。由于这种方式具有单向传递数据的特点,所以这个作为传递消息的共享文件就叫做“管道”。它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的读端读出数据。数据读出之后将从管道中移走,其他读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管道之前,进程将一直阻塞。同样,管道已经满时,进程在试图写管道,在其他进程从管道中移走数据之前,写进程将一直阻塞。

(二)匿名管道

  匿名管道是具有共同祖先的进程之间的一种通信方式,因此通常用于父子进程或者兄弟进程之间的通信,在由父进程创建的子进程将会赋值父进程包括文件在内的一些资源。如果父进程创建子进程之前创建了一个文件,那么这个文件的描述符就会被父进程在随后所创建的子进程所共享。也就是说,父、子进程可以通过这个文件进行通信。

管道通信(上)

 

 

 管道通信(上)

 

 

 参数:长度为2的整型数组

返回值:成功返回0,失败返回-1,errno会被设置,可以通过perror打印错误信息。

函数使用示例:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<unistd.h>
 5 int main(int argc, char const *argv[])
 6 {
 7     int fd_pipe[2];
 8     if(pipe(fd_pipe) == -1)
 9     {
10         perror("pipe");
11         exit(1);
12     }
13     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
14     {
15         perror("write");
16         exit(1);
17     }
18     char buf[128] = "";
19     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
20     {
21         perror("read");
22         exit(1);
23     }
24     printf("%s\n",buf);
25     close(fd_pipe[1]);
26     close(fd_pipe[0]);
27     return 0;
28 }

运行结果:

管道通信(上)

 

 

 父子进程之间通信示例:父进程从终端读取内容,并将内容发送给子进程。

 1 #include<unistd.h>
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 int main(int argc, char const *argv[])
 6 {
 7     int fd_pipe[2];
 8     pid_t pid;
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     if((pid = fork()) == -1)
15     {
16         perror("Fail to fork");
17         exit(1);
18     }
19     else if (pid > 0)
20     {
21         char buf[20] = "";
22         while (1)
23         {
24             if(read(STDIN_FILENO,buf,sizeof(buf)) == -1)
25             {
26                 perror("Fail to read from std");
27                 exit(1);
28             }
29             buf[strlen(buf) - 1] = '\0';
30             if(write(fd_pipe[1],buf,sizeof(buf)) == -1)
31             {
32                 perror("Fail to write to pipe:");
33                 exit(1);
34             }
35             memset(buf,0,sizeof(buf));   
36         }
37     }
38     else if (pid == 0)
39     {
40         char buf[128] = "";
41         while (1)
42         {
43             if(read(fd_pipe[0],buf,1024) == -1)
44             {
45                 perror("Fail to read:");
46                 exit(1);
47             }
48             printf("read from parent by pipe message is %s\n",buf);
49             memset(buf,0,sizeof(buf));
50         }
51            
52     }
53     return 0;
54 }

运行结果:

管道通信(上)

 

 

 (三)匿名管道读写规律

(1)只读不写——当管道有内容时,读取内容,无内容时会进入阻塞态,当我面修改属性为非阻塞时,程序会直接结束。

代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 int main(int argc, char const *argv[])
 7 {
 8     int fd_pipe[2];
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     char buf[128] = "";
15     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
16     {
17         perror("write");
18         exit(1);
19     }
20     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
21     {
22         perror("fail to read");
23         exit(1);
24     }
25     printf("%s\n",buf);
26     memset(buf,0,sizeof(buf));
27     printf("Read again\n");
28     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
29     {
30         perror("fail to read");
31         exit(1);
32     }
33     printf("%s\n",buf);
34     return 0;
35 }

运行结果:

管道通信(上)

 

 

 我们首先在管道内写点数据,进程可以正常的从管道中读取数据,读完之后,管道内没有数据了,此时当我们再读的时候,就会进入阻塞态,我们再试一下,用fcntl使管道为非阻塞,看看会有怎样的效果。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 int main(int argc, char const *argv[])
 7 {
 8     int fd_pipe[2];
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     char buf[128] = "";
15     fcntl(fd_pipe[0],F_SETFL,O_NONBLOCK);
16     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
17     {
18         perror("write");
19         exit(1);
20     }
21     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
22     {
23         perror("fail to read");
24         exit(1);
25     }
26     printf("%s\n",buf);
27     memset(buf,0,sizeof(buf));
28     printf("Read again\n");
29     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
30     {
31         perror("fail to read");
32         exit(1);
33     }
34     printf("%s\n",buf);
35     return 0;
36 }

管道通信(上)

(2)只写不读——管道写满之后就会进入阻塞态

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 int main(int argc, char const *argv[])
 7 {
 8     int fd_pipe[2];
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
15     {
16         perror("write");
17         exit(1);
18     }
19     printf("write successful\n");
20     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
21     {
22         perror("write");
23         exit(1);
24     }
25     printf("write successful\n");
26     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
27     {
28         perror("write");
29         exit(1);
30     }
31     printf("write successful\n");
32     close(fd_pipe[0]);
33     close(fd_pipe[1]);
34     return 0;
35 }

管道通信(上)

我们看到,三次都写成功了,但可以一直写吗?而且管道是有大小的,我们可以写多少呢?

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 int main(int argc, char const *argv[])
 7 {
 8     int fd_pipe[2];
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     int count = 0;
15     while (1)
16     {
17         char buf[1024] = "";
18         if(write(fd_pipe[1],buf,sizeof(buf)) == -1)
19         {
20             perror("write");
21             exit(1);
22         }
23         count++;
24         printf("count = %d\n",count);
25         sleep(1);
26     }
27     
28     close(fd_pipe[0]);
29     close(fd_pipe[1]);
30     return 0;
31 }

管道通信(上)

 

 从程序中不难看出,管道是有大小的,当我们写满之后,就会进入阻塞态。

(3)只有读端——程序会直接结束

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 int main(int argc, char const *argv[])
 7 {
 8     int fd_pipe[2];
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     close(fd_pipe[1]);
15     char buf[128] = "";
16     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
17     {
18         perror("read");
19         exit(1);
20     }
21     printf("%s\n",buf);
22     close(fd_pipe[0]);
23     return 0;
24 }

管道通信(上)

 

 按道理来讲,此时读管道应该进入阻塞态的,但由于我们关闭了写端,所以程序就直接结束了。

(4)只有写端——管道会破裂

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 int main(int argc, char const *argv[])
 7 {
 8     int fd_pipe[2];
 9     if(pipe(fd_pipe) == -1)
10     {
11         perror("fail to pipe");
12         exit(1);
13     }
14     close(fd_pipe[0]);
15     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
16     {
17         perror("write");
18         exit(1);
19     }
20     printf("write successful\n");
21     close(fd_pipe[1]);
22     return 0;
23 }

管道通信(上)

 

 我们运行发现程序直接结束了,其实这里大家要知道一点,就是只有写端的时候,我们写内容时是有一个SIGPIPE信号产生的,表明管道破裂了,我们可以通过一个函数——signal()来看。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 #include<string.h>
 5 #include<fcntl.h>
 6 #include<signal.h>
 7 void hander(int sig)
 8 {
 9     printf("SIGPIPE occurrenced\n");
10     exit(1);
11 }
12 int main(int argc, char const *argv[])
13 {
14     signal(SIGPIPE,hander);
15     int fd_pipe[2];
16     if(pipe(fd_pipe) == -1)
17     {
18         perror("fail to pipe");
19         exit(1);
20     }
21     close(fd_pipe[0]);
22     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
23     {
24         perror("write");
25         exit(1);
26     }
27     printf("write successful\n");
28     close(fd_pipe[1]);
29     return 0;
30 }

管道通信(上)

 

上一篇:thinkphp 6.0 使用tinyMCE image 图片上传插件应该注意的问题


下一篇:2021-09-25 文件目录和进程基础