linux命名管道:fifo
一、命名管道
除了创建方式,FIFO文件与管道极为相似。FIFO是非匿名的管道,通过系统调用mkfifo()存在于文件系统中。
二、FIFO相关函数
函数名称 | int mkfifo(const char *pathname, mode_t mode) |
---|
头文件 | <sys/types.h><sys/stat.h> |
函数参数 | 说明 |
pathname | 创建FIFO所用的路径名 |
mode | 指定FIFO的属性 |
返回值 | 成功:0,失败:-1 |
函数名称 | int open(const char *pathname, int flags) |
---|
参数 | 说明 |
头文件 | <sys/types.h><sys/stat.h><fcntl.h> |
pathname | 打开的目标文件 |
flags | 打开方式 |
返回值 | 成功:文件描述符,失败:-1 |
flags(必须为一下三个参数中的一个):
O_RDONLY,O_WRONLY,O_RDWR
函数名称 | ssize_t read(int fd, void *buf, size_t count) |
---|
头文件 | <unistd.h> |
参数 | 说明 |
fd | 目标文件描述符 |
buf | 读取数据的缓存 |
count | 此次读取的最多字节数 |
返回值 | 成功:此次读取的字节数,失败:-1 |
函数名称 | int stat(const char *path, sturct stat *buf) |
---|
头文件 | <sys/types.h><sys/stat.h><unistd.h> |
参数 | 说明 |
path | 指定要操作的目标文件路径 |
buf | 文件属性存储的结构体缓存地址 |
返回值 | 成功:0,失败:-1 |
函数名称 | mode_t umask(mode_t mask) |
---|
头文件 | <sys/types.h><sys/stat.h> |
参数 | 说明 |
mask | 要替换的模式掩码 |
返回值 | 原mask值 |
函数名称 | ssize_t write(int fd, const void *buf, size_t count) |
---|
头文件 | <unistd.h> |
参数 | 说明 |
fd | 操作的文件描述符 |
buf | 写入数据的缓存首地址 |
count | 此次写入数据的最大字节数 |
返回值 | 成功:写入的字节数,失败:-1 |
函数名称 | int mkfifoat(int dirfd, const char *pathname, mode_t mode) |
---|
头文件 | <fcntl.h><sys/stat.h> |
参数 | 说明 |
dirfd | 目录文件描述符 |
pathname | 路径 |
mode | 创建模式 |
返回值 | 成功:0,失败:-1 |
与mkfifo()的异同:
二者创建命名管道的方式是相同的;
当pathname指定的路径为相对路径时,mkfifo()是以进程的工作路径为基础,而mkfifoat()以dirfd所引用的目录路径为基础路径来创建命名管道;
当pathname指定的路径为绝对路径时,dirfd参数被忽略;
在pathname为相对路径的情况下,若dirfd的值为AT_FDCWD,则pathname被解释为与进程的工作目录相对的相对路径(同mkfifo())。
三、相关介绍
一个FIFO特殊文件(命名管道)与管道相似,不同的是FIFO是作为文件系统的一部分被访问的。它可以被多个进程进行读、写。当多个进程通过FIFO进行数据交换时,内核在内部进行数据传送,并不将数据写入文件系统。因此,FIFO文件在文件系统中没有任何内容。FIFO在文件系统中的访问入口仅作为一个引用指针,使得各进程可以在文件系统中访问它。
内核仅为每个被进程打开的FIFO维持一个实例,且只有双端(读端、写端)都被打开时才可以进行数据传输。通常情况下,打开一个FIFO会阻塞至对端也被打开。
进程可通过非阻塞方式打开一个FIFO。在此情况下,以只读方式打开的一端将会成功,以只写打开的一端将会失败,并返回ENXIO(没有此设备或地址),除非对端(即读端)早已被打开。
在linux下,以阻塞或非阻塞的方式打开一个FIFO进行读或写都会成功。POSIX将此视为未定义行为。当同一线程同时使用读、写端与自身进行通信时,需要十分小心地避免死锁。
四、测试代码
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<iostream>
int main()
{
mode_t mode = S_IWOTH | S_IROTH;
if(-1 == mkfifo("./namedpipe", mode))
{
perror("Mkfifo:");
return -1;
}
pid_t p_id = fork();
if(0 > p_id)
{
perror("Precess Creation:");
return -1;
}
if(0 == p_id)
{
//父进程;
int r_end = open("./namedpipe", O_RDONLY);
std::cout << " Open the read end of the fifo. " << std::endl;
if(-1 == r_end)
{
std::cout << __LINE__ << " ";
perror("Open namedpipe:");
return -1;
}
char buf[1024] = {0x00};
ssize_t r_bytes = 0;
size_t l_bytes = 0;
while(true)
{
memset(buf, 0x00, sizeof(buf));
r_bytes = read(r_end, buf, sizeof(buf));
if(-1 == r_bytes)
{
std::cout << __LINE__ << " ";
perror("Read end:");
}
if(0 < r_bytes)
{
std::cout << "Recv data: " << buf << std::endl;
}
}
}
else
{
//子进程:写端
int w_end = open("./namedpipe", O_WRONLY);
if(-1 == w_end)
{
std::cout << __LINE__ << " ";
perror("Open named fifo of w_end: ");
return -1;
}
ssize_t w_bytes = 0;
char buf[1024] = "Hello parent precess, I am greet to you by a fifo data dealer.";
int loop_cnt = 5;
while (loop_cnt--)
{
sleep(3);
w_bytes = write(w_end, buf, strlen(buf));
if(-1 == w_bytes)
{
std::cout << __LINE__ << " ";
perror("Write data: ");
}
}
return 0;
}
return 0;
}