赞
踩
目录
1.定义
管道是Linux/UNIX系统中比较原始的进程间通信形式(简单的理解为两个进程之间通讯的方式),它将数据以一种数据流的方式,在多进程间流动。在系统中其相当于文件系统上的一个文件,来缓存所要传输的数据。
这里我们要了解三个概念:
管道是半双工的,如果需要双方通讯时,则需要建立两个管道。
我们知道在Linux中有句话叫做“万物皆文件”,管道也是这样,它也是一个文件,只不过它比较特殊。它单独构成一种独立的文件系统。管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中。
2.管道文件和普通文件的区别
我们知道当我们从一个文件中读取完数据后,这些数据依然存在于这个文件中。但当管道中的数据被读出时,管道中就没有数据了。因此从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便后续写入更多的数据。当管道中所有的数据都已被读取时,管道变为空,如果这时继续对管道进行读操作时,读操作将会被阻塞,直到某些数据被写入。
当我们在写入数据时,一般不需要考虑文件是否能够容纳下我们即将写入的数据。但是管道文件就不一样了,当我们在向管道写入文件时,管道可能会变满,当这种情况发生时,随后对管道进行的写入操作将会被阻塞,直到管道中的某些数据被读取,腾出足够的空间后写操作才会继续被执行。
3.管道的大小
管道是内核管理的一个固定大小的缓冲区,该缓冲区的大小为1 页,即4KB。
注:管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式。
4.管道的分类
管道没有名字,所以也称为匿名管道,由匿名管道我们又衍生出另一种管道,即命名管道。
1.匿名管道的特点
2.匿名管道的创建与关闭
函数:
- #include <unisted>
- int pipe(int fd[2]);
功能:创建一个匿名管道
参数:参数fd[2]是一个长度为2的文件描述符数组,其中fd[0]是读出端的文件描述符,fd[1]是写入端的文件描述符。当函数成功返回后,则自动维护了一个从fd[1]到fd[0]的数据通道。
返回值:成功返回 0,失败返回 -1
管道的关闭:close函数
3.管道的读写
我们分别使用read和write函数来对管道进行读和写操作。
注意:管道的两端是固定了任务的。即管道的读出端只能用于读取数据,管道的写入端只能用于写入数据。
管道的读取规则:
管道的写入规则
4.示例代码
父进程利用管道向子进程发送消息
- #include <fcntl.h>
- #include <stdio.h>
- #include <assert.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
-
- int main()
- {
- int fd[2];
- pipe(fd);
-
- pid_t pid = fork();
- assert(pid != -1);
- if(pid == 0)
- {
- close(fd[1]);
- char buff[128] = {0};
- read(fd[0],buff,127);
- printf("[child]buff:%s\n",buff);
- close(fd[0]);
- }
- else
- {
- close(fd[0]);
- printf("[parent]input:");
- char buff[128]={0};
- fgets(buff,128,stdin);
- write(fd[1], buff, strlen(buff));
- close(fd[1]);
- }
- exit(0);
- }

执行结果:
1.命名管道的特点
2.命名管道的创建
函数:
- #include <sys/types.h>
- #include <sys/stat.h>
- int mkfifo(const char *pathname , mode_t mode);
功能:创建一个命名管道
参数:该函数的第一个参数是一个普通的路径名,也就是创建后FIFO文件的名字。第二个参数与打开普通文件的open函数中的mode参数相同。
pathname:一个Linux路径名,它是FIFO的名字。即每个FIFO与一个路径名相对应;
mode:指定的文件权限位,类似于open函数的第三个参数。即创建该FIFO时,指定用户的访问权限,有以下值:S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP,S_IROTH,S_IWOTH。
返回值:mkfifo函数默认指定O_CREAT | O_EXECL方式创建FIFO,如果创建成功,直接返回0。如果FIFO已经存在,则创建失败,会返回-1并且errno置为EEXIST。对于其他错误,则置响应的errno值;
另外,我们也可以直接使用系统命令mkfifo直接创建一个管道文件。
3.示例代码
创建一个命名管道
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- int main(int argc , char *argv[])
- {
- mode_t mode = 0666;
- if(argc != 2)
- {
- printf("error\n");
- exit(0);
- }
- if(mkfifo(argv[1], mode) < 0 )
- {
- perror("failed to mkfifo\n");
- exit(0);
- }
- else
- {
- printf("Success!\n");
- }
- exit(0);
- }

执行结果:
使用命令mkfifo创建命名管道
若要删除一个命名管道,则使用系统调用unlink
4.命名管道的使用
当创建一个FIFO后,它必须以只读方式打开或者只写方式打开,所以可以用open函数,当然也可以使用标准的文件I/O打开函数,例如fopen来打开。也就是说命名管道FIFO比管道多了一个打开操作open。原因很简单,命名管道是Linux下的一种文件类型,而管道不是。
mkfifo的一般使用方式是:通过mkfifo创建FIFO -> 然后调用open -> 以读或者写的方式之一打开FIFO -> 然后进行数据通信。
5.命名管道的读写
从命名管道中读取数据的规则:
如果一个进程为了从FIFO中读取数据而阻塞打开了FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。
如果有进程写打开FIFO,且当前FIFO为空,则对于设置了阻塞标志的读操作来说,将一直阻塞下去,直到有数据可以读时才继续执行;对于没有设置阻塞标志的读操作来说,则返回0个字节,当前errno值为EAGAIN,提醒以后再试。
对于设置了阻塞标志的读操作来说,造成阻塞的原因有两种:当前FIFO内有数据,但有其它进程在读这些数据;另外就是FIFO内没有数据。解阻塞的原因是:FIFO中有新的数据写入,不论写入数据量的大小,也不论读操作请求多少数据量,只要有数据写入即可。
读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程中有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)。
如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。
如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数少于请求的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。
从命名管道中写入数据的规则:
6.代码
两个进程利用命名管道通讯
write.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-
- int main(int argc,char* argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("myfifo",0600);
- if(ret != 0)
- {
- perror("mkfifo error");
- }
- fd = open("myfifo",O_WRONLY);
- if(fd < 0)
- {
- perror("open fifo error");
- }
- char buff[128] = "Hello World!";
- write(fd,buff,strlen(buff));
- printf("write to myfifo buff=%s\n",buff);
- while(1);
- close(fd);
- exit(0);
- }

read.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-
- int main(int argc,char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("myfifo",0600);
- if(ret != 0)
- {
- perror("mkfifo error");
- }
- fd = open("myfifo",O_RDONLY);
- if(fd < 0)
- {
- perror("open fifo error");
- }
- while(1)
- {
- char buff[128]={
- 0
- };
- read(fd,buff,sizeof(buff));
- printf("read from myfifo buff=%s\n",buff);
- sleep(1);
- }
- close(fd);
- exit(0);
- }

执行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。