文章目录
无名管道的缺点:只能在父子进程或者其它具有亲缘关系的进程间进行数据传输。
有名管道:可以在任意进程之间传输。
mkfifo() 函数
头文件
#include<sys/types.h>
#include<sys/stat.h>
函数原型
filename就是有名管道的名字,mode表示rwx权限
int mkfifo(const char *filename,mode_t mode);
返回值:
成功:0
失败:-1
特点:
-
有文件名,可以使用open() 函数打开
-
可以实现任意进程间的数据传输
-
write() 和 read() 可能会阻塞进程:空读 or 满写
-
write()操作具有原子性。无名管道缓存只要由任意的空闲空间,那么write就可以往里面写;而有名管道在write之前会检查有名管道的空闲空间,确认空闲空间充足的情况下,才会去执行写操作,否则不会写。
使用步骤:
- 在第一个进程里面利用 mkfifo() 创建有名管道。
- open() 打开有名管道,write() / read() 数据。
- close() 有名管道。
- 第二个进程open() 有名管道,read() / write() 数据。
- close() 有名管道。
测试程序
注意不要自己手动创建管道文件!!!运行会发生异常!!!
让 fifo_read 进程 自己创建才能正常工作!!!
fifo_read.c
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#include<unistd.h>
#include<string.h>
//有名管道文件名
#define MYFIFO "./myfifo"
//4096,定义在 limits.h 中
#define MAX_BUFFER_SIZE PIPE_BUF
//参数为即将写入的字符串
int main(int argc,char **argv)
{
char buf[MAX_BUFFER_SIZE];
int fd;
int nread;
//判断有名管道是否存在,若不存在,则以相应的权限创建
if(-1 == access(MYFIFO,F_OK))
{
if((mkfifo(MYFIFO,0666) < 0) && (errno != EEXIST))
{
printf("Can not create fifo file.\n");
exit(0);
}
}
//以只读方式打开有名管道
fd = open(MYFIFO,O_RDONLY);
if(-1 == fd)
{
printf("Open fifo file error.\n");
exit(1);
}
//循环读取有名管道数据
while(1)
{
memset(buf,0,sizeof(buf));
if((nread = read(fd,buf,MAX_BUFFER_SIZE)) > 0)
{
/* 每一次都为 4096, 内存的页大小,
* 管道规则:
* 1、满写阻塞,空读阻塞
* 2、没写满不能读,没读空不能写
* 3、半双工通信,读写教程互斥访问管道
* 4、通信数据是字节流形式
* 5、读完后管道中的数据丢弃
*/
printf("nread = %d\n", nread);
printf("Read '%s' from fifo.\n",buf);
}
}
close(fd);
exit(0);
}
fifo_write.c
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#include<unistd.h>
#include<string.h>
//有名管道文件名
#define MYFIFO "./myfifo"
//4096,定义在 limits.h 中
#define MAX_BUFFER_SIZE PIPE_BUF
int main(int argc,char **argv)
{
int fd;
char buf[MAX_BUFFER_SIZE];
int nwrite;
if(argc <= 1)
{
printf("Usage: ./fifo_write string.\n");
exit(1);
}
//填充命令行第一个参数到buf
sscanf(argv[1],"%s",buf);
//以只写阻塞方式打开fifo管道
fd = open(MYFIFO,O_WRONLY);
if(-1 == fd)
{
printf("Open fifo file error.\n");
exit(1);
}
//向管道中写入字符串
if((nwrite = write(fd,buf,MAX_BUFFER_SIZE)) > 0)
{
/* 每次都是 4096 */
printf("nwrite = %d\n", nwrite );
printf("Write '%s' to fifo.\n",buf);
}
close(fd);
exit(0);
}
测试结果
- 编译
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ ls
fifo_read.c fifo_write.c
jl@jl-virtual-machine:~/test/11_1$ gcc fifo_read.c -o fifo_read
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ gcc fifo_write.c -o fifo_write
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ ls
fifo_read fifo_read.c fifo_write fifo_write.c
jl@jl-virtual-machine:~/test/11_1$
- 打开一个终端,在这个终端1中,先运行fifo_read,由于管道是空的,可以看到进程被read() 阻塞了,shell无终端控制权
jl@jl-virtual-machine:~/test/11_1$ ./fifo_read
- 打开另一个终端,就叫它终端2,运行fifo_write,向管道里面写入数据
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ ./fifo_write 666
Write '666' to fifo.
jl@jl-virtual-machine:~/test/11_1$ ./fifo_write 777
Write '777' to fifo.
jl@jl-virtual-machine:~/test/11_1$
此时终端1中:
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$
jl@jl-virtual-machine:~/test/11_1$ ./fifo_read
Read '666' from fifo.
Read '777' from fifo.
重点
任意进程之间数据传输。
写是原子操作类型。
设置写的size是4096,每次写都会阻塞在write,直到接收进程 read 4096。
而且同时运行两个接收方进程,写一次只能有一个进程接收到发送方内容。