命名管道
(一)命名管道不同于匿名管道指出是它提供了一个路径名,以FIFO的文件形式存在于文件系统中,这样即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交互数据。
命名管道(FIFO)和匿名管道(pipe)有一些特点是相同的,不一样的地方在于:
1.FIFO在文件系统中作为一个特殊的文件而存在,但是FIFO中的内容却存放在内存中。
2.当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便后面使用。
3.FIFO有名字,不相关的进程可以通过打开命名管道进行通信。
(二)命名管道的创建
1.所需头文件:
#include <sys/types.h>
#include <sys/stat.h>
2.函数:
int mkfifo(const char* pathname,mode_t mode);//功能是创建一个命名管道
3.参数:
(1)pathname:普通的路径名,也就是创建管道的名字。
(2)mode:文件的权限,与打开普通文件的open()函数的mode参数一样。
4.返回值:
(1)成功:0
(2)失败:-1
实例:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main()
{
int ret;
ret = mkfifo("myfifo",0666);
if(ret == -1)
{
perror("mkfifo error");
}
return 0;
}
(三)命名管道的一些操作
1.后期的操作,把这个命名管道当作普通文件一样进行操作:open()、write()、read()、close()。但是和无名管道一样,需要考虑其阻塞特性。
下面验证的是open()的时候没有指定非阻塞标志(O_NONBLOCK)。
(1)
- 当open()以只读方式打开FIFO时,要阻塞到某个进程为写而打开FIFO
- 当open()以只写方式打开FIFO时,要阻塞到某个进程为读而打开FIFO
- 总之就是一句话:只读等着只写,只写等着只读,都有两个条件都成立,才会往下执行。
read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int ret;
ret = mkfifo("myfifo1",0666);
if(ret == -1)
{
perror("mkfifo error");
}
printf("before open\n");
fd = open("myfifo1",O_RDONLY);
if(fd<0)
{
perror("open error");
}
printf("after open\n");
return 0;
}
write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int ret;
ret = mkfifo("myfifo1",0666);
if(ret == -1)
{
perror("mkfifo error");
}
printf("before open\n");
fd = open("myfifo1",O_WRONLY);
if(fd<0)
{
perror("open error");
}
printf("after open\n");
return 0;
}
结果动态演示:
当然也可以设置以可读可写方式打开,这样,调用open()函数时就不会阻塞了。
(2)假如FIFO中没有数据,调用read()函数从FIFO里读数据时,read()也会阻塞。这个特点和无名管道是一样的。
open_read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
int ret;
ret = mkfifo("myfifo2",0666);
if(ret == -1)
{
perror("mkfifo error");
}
printf("before open\n");
fd = open("myfifo1",O_RDWR);
if(fd<0)
{
perror("open error");
}
printf("after open\n");
char buf[1024];
printf("before read\n");
read(fd,buf,sizeof(buf));
printf("after read\n");
return 0;
}
open_write.c
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int ret;
ret = mkfifo("myfifo2",0666);
if(ret == -1)
{
perror("mkfifo error");
}
printf("before open\n");
fd = open("myfifo1",O_WRONLY);
if(fd<0)
{
perror("open error");
}
printf("after open\n");
char buf[1024] = "hello world";
printf("before write\n");
write(fd,buf,strlen(buf));
printf("after write\n");
return 0;
}
运行效果展示:
(3)通信过程中若写进程推出了,就算命名管道里没有数据,调用read()函数从FIFO里读数据时不阻塞;若写进程有重新运行,调用read()函数从FIFO里读数据时又恢复阻塞。
(4)通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到SIPIPE信号)退出。
(5)调用write()函数向FIFO里写数据,当缓冲区已满时,write()也会阻塞。
这两个管道和无名管道是一样的。