无名管道与有名管道
无名管道:
- 只能用于亲缘进程间通信
- 半双工的通信模式,具有固定的读端和写端,在文件系统中不可见
- 管道可以看作一种特殊的文件,对于它的读写可以使用文件IO,如read(),write()等函数
有名管道:
- 有名管道可以使互不相关的两个进程互相通信(全双工),并且有名管道在文件系统中可见,可以通过路径名指出
- 进程通过IO操作有名管道,但不支持像lseek()的操作
- 有名管道遵循先进先出
管道读写注意事项:
- 当管道中无数据时,读操作会阻塞
- 向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那写操作将会一直阻塞
- 只有在管道读端存在时,向管道中写入数据才有意义,否则向管道写入数据的进程将收到内核传来的SIGPIPE信号
有名管道实现文件传输
创建管道:
创建管道用于进程间通信
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
int main()
{
int ret = mkfifo("./myfifo",0777);
if(-1 == ret)
{
perror("mkfifo");
return -1;
}
printf("mkfifo success.\n");
return 0;
}
写管道
从文件读取数据,并将文件写入管道
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(int argc,char* argv[])
{
if(argc < 2)
{
printf("please enter the %s file\n",argv[0]);
return -1;
}
char buf[64];
int fd = open("./myfifo",O_WRONLY);
if(-1 == fd)
{
perror("open");
return -1;
}
int fd2 = open(argv[1],O_RDONLY);
if(-1 == fd2)
{
perror("open");
return -1;
}
int ret;
while(1)
{
ret = read(fd2,buf,sizeof(buf));
if(ret != 0)
{
write(fd,buf,ret);
}
else break;
}
close(fd);
return 0;
}
读管道
从管道中读取数据并写入文件
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(int argc,char* argv[])
{
if(argc < 2)
{
printf("please enter the %s file\n",argv[0]);
return -1;
}
char buf[64];
int fd = open("./myfifo",O_RDONLY);
if(-1 == fd)
{
perror("open");
return -1;
}
int fd2 = open(argv[1],O_WRONLY);
if(-1 == fd2)
{
perror("open");
return -1;
}
int ret;
while(1)
{
ret = read(fd,buf,sizeof(buf));
if(ret != 0)
{
write(fd2,buf,ret);
}
else break;
}
close(fd);
return 0;
}
结果测试
两个进程分别读写,将test.txt写入test2.txt中,比较两个文件没有差异
ps:上述的传输不通过管道,通过一个普通文件保存数据也可以做到。但是:
命名管道的文件不是用来承载数据的,而且用来做地址用的,操作的时内存空间,比起操作磁盘空间,效率是要高很多的。