什么是管道?
管道就是内核当中的一块缓冲区(一块内存),进程A和进程B可以通过这个缓冲区进行交换数据,匿名管道不具备标识符
#include
功能:创建一无名管道
原型: int pipe(int pipefd[2]);
参数:pipefd:文件描述符数组,其中有两个元素,分别是pipefd[0]和pipefd[1],它们当中保存的是一个文件描述符
pipefd[0]表示读端,不能写可读,pipefd[1]表示写端,不能读可写
(参数为输出型参数)返回值:创建成功返回0,创建失败返回-1.
探究点:pipefd[0]、pipefd[1]当中的值是pipe函数进行赋值的,直白的说,当我们调用pipe函数的时候,只需要给pipe函数传递一个拥有两个元素的整型数据的数组,pipe函数在创建完毕管道之后,会给pipefd[0]、pipefd[1]进行赋值。
下面是代码创建管道的一个演示:
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 int fd[2];
7 int ret=pipe(fd);
8 if(ret<0)
9 {
10 perror("pipe");
11 return 0;
12 }
13 pid_t pid=fork();
14 if(pid<0)
15 {
16 perror("fork");
17 return 0;
18 }
19 else if(pid==0)
20 {
21 //child
22 char buf[1024]={
0};
23 read(fd[0],buf,sizeof(buf)-1);
24 printf("child read:%s\n",buf);
25
26 }
27 else
28 {
29 //father
30 write(fd[1],"I am father",11);
31 }
32 }
fcntl函数:设置/获取文件描述符的属性
int fcntl(int fd,int cmd,.../*arg*/);
fd:文件描述符
cmd: F_GETFL:获取文件描述符的属性(可变参数列表就可以不用传递任何值) eg:fcntl(fd[0],F_GETFL)
F_SETFL:设置文件描述符的属性
可变参数列表为:O_RDONLY(只读)/O_WRONLY(只写)/O_RDWR(可读可写)
O_NONBLOCK(非阻塞属性) 都采用按位或的方式
eg:fcntl(fd[0],F_SETFL,flag0|O_NONBLOCK);
返回值:如果是获取(F_GETFL),返回文件描述符的属性。
1 #include<stdio.h>
2 //fcntl函数
3 #include<fcntl.h>
4 #include<unistd.h>
5
6 int main()
7 {
8 int fd[2];
9 int ret=pipe(fd);//创建一个管道
10 if(ret<0)
11 {
12 perror("pipe");
13 return 0;
14 }
15
16 int flag0=fcntl(fd[0],F_GETFL);//获取管道属性
17 printf("read fd[0]:flag:%d\n",flag0);
18 int flag1=fcntl(fd[1],F_GETFL);
19 printf("write fd[1]:flag:%d\n",flag1);
20
21 // fcntl(fd[0],F_SETFL,flag0|O_NONBLOCK);//设置管道为非阻塞形式
22 // printf("read fd[0]:flag:%d\n",flag0);
23 // fcntl(fd[1],F_SETFL,flag1|O_NONBLOCK);
24 // printf("write fd[1]:flag:%d\n",flag1);
25
26 return 0;
27 }
这里可以看到fd[0]和fd[1]的属性,分别为0和1,这里再进行讨论一下源码,可以看到O_RDONLY和O_WRONLY的表示为00000000和00000001,这样我们就可以联想到为什么要用或的方式,将特定位置置为1,就可以表示出特定的属性。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<errno.h>
5
6 void SetNonBlock(int fd)
7 {
8 int flag=fcntl(fd,F_GETFL);
9 fcntl(fd,F_SETFL,flag|O_NONBLOCK);
10 }
11
12 int main()
13 {
14 int fd[2];
15 int ret=pipe(fd);
16 if(ret<0)
17 {
18 perror("pipe");
19 return 0;
20 }
21
22 ret=fork();
23 if(ret<0)
24 {
25 perror("fork");
26 return 0;
27 }
28 else if(ret==0)
29 {
30 //child
31 close(fd[0]);
32 close(fd[1]);
33 while(1)
34 {
35 sleep(1);
36 }
37 }
38 else
39 {
40 //father
41 close(fd[1]);
42 SetNonBlock(fd[0]);
43
44 char buf[1024]={
0};
45 int read_size=read(fd[0],buf,sizeof(buf)-1);
46 printf("read_size:%d,buf:%s\n",read_size,buf);
47 }
48 return 0;
49
50 }
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<errno.h>
5
6 void SetNonBlock(int fd)
7 {
8 int flag=fcntl(fd,F_GETFL);
9 fcntl(fd,F_SETFL,flag|O_NONBLOCK);
10 }
11
12 int main()
13 {
14 int fd[2];
15 int ret=pipe(fd);
16 if(ret<0)
17 {
18 perror("pipe");
19 return 0;
20 }
21
22 ret=fork();
23 if(ret<0)
24 {
25 perror("fork");
26 return 0;
27 }
28 else if(ret==0)
29 {
30 //child
31 close(fd[0]);
32 SetNonBlock(fd[1]);
33 //写端不关闭
34 while(1)
35 {
36 sleep(1);
37 }
38 }
39 else
40 {
41 //father
42 close(fd[1]);
43 SetNonBlock(fd[0]);
44
45 char buf[1024]={
0};
46 int read_size=read(fd[0],buf,sizeof(buf)-1);
47 if(read_size<0)
48 {
49 if(errno==EAGAIN)
50 {
51 printf("管道为空\n");
52 printf("read_size:%d,buf %s\n",read_size,buf);
53 }
54 }
55 }
56 return 0;
57
58 }
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<errno.h>
5
6 void SetNonBlock(int fd)
7 {
8 int flag=fcntl(fd,F_GETFL);
9 fcntl(fd,F_SETFL,flag|O_NONBLOCK);
10 }
11
12 int main()
13 {
14 int fd[2];
15 int ret=pipe(fd);
16 if(ret<0)
17 {
18 perror("pipe");
19 return 0;
20 }
21
22 ret=fork();
23 if(ret<0)
24 {
25 perror("fork");
26 return 0;
27 }
28 else if(ret==0)
29 {
30 //child
31 close(fd[0]);
32 SetNonBlock(fd[1]);
33 int count=0;
34 while(1)
35 {
36 int write_size=write(fd[1],"a",1);
37 if(write_size<0)
38 {
39 printf("write_size:%d\n",write_size);
40 if(errno==EAGAIN)
41 {
42 //将管道写满了
43 break;
44 }
45 }
46 printf("count:%d\n",count++);
47 }
48
49 while(1)
50 {
51 sleep(1);
52 }
53 }
54 else
55 {
56 //father
57 close(fd[1]);
58 close(fd[0]);
59 while(1)
60 {
61 sleep(1);
62 }
63 }
64 return 0;
65
66 }
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<errno.h>
5
6 void SetNonBlock(int fd)
7 {
8 int flag=fcntl(fd,F_GETFL);
9 fcntl(fd,F_SETFL,flag|O_NONBLOCK);
10 }
11
12 int main()
13 {
14 int fd[2];
15 int ret=pipe(fd);
16 if(ret<0)
17 {
18 perror("pipe");
19 return 0;
20 }
21
22 ret=fork();
23 if(ret<0)
24 {
25 perror("fork");
26 return 0;
27 }
28 else if(ret==0)
29 {
30 //child
31 close(fd[0]);
32 SetNonBlock(fd[1]);
33 int count=0;
34 while(1)
35 {
36 int write_size=write(fd[1],"a",1);
37 if(write_size<0)
38 {
39 printf("write_size:%d\n",write_size);
40 if(errno==EAGAIN)
41 {
42 //将管道写满了
43 break;
44 }
45 }
46 printf("count:%d\n",count++);
47 }
48
49 while(1)
50 {
51 sleep(1);
52 }
53 }
54 else
55 {
56 //father
57 close(fd[1]);
58 //close(fd[0]);
59 while(1)
60 {
61 sleep(1);
62 }
63 }
64 return 0;
65
66 }
命名管道也是在内核当中开辟了一块缓冲区,这块缓冲区具有标识符,可以被任何进程通过标识符去找到。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/shm.h>
4
5 #define key 0x23232323
6
7 int main()
8 {
9 int shmid=shmget(key,1024,IPC_CREAT|0664);
10 if(shmid<0)
11 {
12 perror("shmget");
13 return 0;
14 }
15 return 0;
16 }
(2)创建A_write.c,向管道中写入"I am process A"
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<fcntl.h>
4
5 int main()
6 {
7 int fd=open("_shm.c",O_RDWR);
8 if(fd<0)
9 {
10 perror("open");
11 return 0;
12 }
13
14 while(1)
15 {
16 write(fd,"I am process A",14);
17 sleep(1);
18 }
19 close(fd);
20 return 0;
21
22 }
(2)创建B_read.c,从管道中读出数据
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<fcntl.h>
4
5 int main()
6 {
7 int fd=open ("_shm.c",O_RDWR);
8 if(fd<0)
9 {
10 perror("open");
11 return 0;
12 }
13 while(1)
14 {
15 char buf[1024]={
0};
16 read(fd,buf,sizeof(buf)-1);
17
18 printf("buf: %s\n",buf);
19 sleep(1);
20 }
21 close(fd);
22 return 0;
23 }