有名管道FIFO

管道和FIFO的特征之一是它们的数据是一个字节流。这是UNIX的原生I/O模型。进程往其中写入的是字节流,系统不对它作解释。

mkfifo 既是命令也是函数

作为命令:mkfifo pzh  为创建一个名为pzh 的有名管道

1. 作为函数:mkfifo

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

【注意】

mkfifo已隐含指定O_CREAT|O_EXCL。即它要么创建一个新的FIFO,要么返回一个EEXIST错误。如果不希望创建一个新的FIFO,那就应调用open而不是mkfifo。

要打开一个已存在的FIFO或创建一个新的FIFO,应先调用mkfifo,检查它是否返回EEXIST错误,若返回则改为调用open。

2.open函数

扫描二维码关注公众号,回复: 2371847 查看本文章
open(const char *path, O_RDONLY);//1
open(const char *path, O_RDONLY | O_NONBLOCK);//2
open(const char *path, O_WRONLY);//3
open(const char *path, O_WRONLY | O_NONBLOCK);//4

1、就是程序不能以O_RDWR(读写)模式打开FIFO文件进行读写操作,而其行为也未明确定义,因为如一个管道以读/写方式打开,进程就会读回自己的输出,同时我们通常使用FIFO只是为了单向的数据传递。

2、就是传递给open的是FIFO的路径名,而不是文件名。

3.第二个参数中的选项O_NONBLOCK,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的。

以只读方式和只写方式打开文件时要注意:

读端打开,如果写端已打开则打开操作成功返回,如果写端没打开,则读端阻塞。如果是非阻塞函数,则成功返回,(读到文件结束标志)

写端打开,如果读端已打开则打开操作成功返回,如果读端没打开,则写端阻塞。如果是非阻塞函数,则返回ENXIO错误产生信号SIGPIPE

FIFO中读取数据

1. 读端的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)。

2. 对于设置了阻塞标志的读操作说,造成阻塞的原因有两种:当前FIFO内有数据,但有其它进程在读这些数据;另外就是FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,不论信写入数据量的大小,也不论读操作请求多少数据量。

就是说读操作同时只可以有一个进程进行,

3. 如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直阻塞。对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。

FIFO中写入数据:

1.对于设置了阻塞标志的写操作:

  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。
  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。(这时读端可能间歇性得到数据)

2.对于没有设置阻塞标志的写操作:

  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写;
  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。

FIFO内核实现时可以支持双向通信。(pipe单向通信,因为父子进程共享同一个file 结构体

先关闭只读方式打开的文件,再以只写方式打开文件。这样就可以实现双向通信了。但最好使用一对FIFO

验证代码:

先写后读:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MSG "hello"
int main()
{
    int fd;
    fd = open("./fio",O_WRONLY);
    printf("w:send msg:%s\n",MSG);
    write(fd,MSG,sizeof(MSG));
    sleep(5);
    close(fd);
    fd = open("./fio",O_RDONLY);
    char buf[1024];
    memset(buf,0,sizeof(buf));
    read(fd,buf,sizeof(buf));
    printf("w,recv:%s\n",buf);

}

先读后写:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
    int fd;
    fd = open("./fio",O_RDONLY);
    char buf[1024];
    memset(buf,0,sizeof(buf));
    read(fd,buf,sizeof(buf));
    printf("r:recv msg:%s\n",buf);

    sleep(5);
    close(fd);
    fd = open("./fio",O_WRONLY);
    printf("r:send:%s\n","fighting");
    write(fd,"fighting",9);

}

安全问题:

个FIFO文件,有多个进程同时向同一个FIFO文件写数据,而只有一个读FIFO进程在同一个FIFO文件中读取数据时,会发生数据块的相互交错。

根据上面的知识我们知道:

如果所有的写请求都是发往一个阻塞的FIFO的,并且每个写记请求的数据长度小于等于PIPE_BUF字节,系统就可以确保数据决不会交错在一起。

猜你喜欢

转载自www.cnblogs.com/Lune-Qiu/p/9368051.html