• 有名管道FIFO


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

    FIFO不存数据,只是通过它找到内核文件。

    一.建立有名管道

    1.命令mknod   :

    mknod  name  p/s/m    //创建管道文件/信号量/共享内存

    2.命令mkfifo 创建管道

    mkfifo -m 664 k2     //创建一个访问权限为664的管道文件k2 

    3作为函数:mkfifo

    #include <sys/types.h>

    #include <sys/stat.h>

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

    【注意】

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

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

    另:open函数

    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
    ",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
    ",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
    ",buf);
    
        sleep(5);
        close(fd);
        fd = open("./fio",O_WRONLY);
        printf("r:send:%s
    ","fighting");
        write(fd,"fighting",9);
    
    }

    安全问题:

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

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

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

    模型:

    1-1

    n-1

    n-1-n

     fgets,它读取以换行符“ ”结尾的字符串.

    小结:

    管道文件。它占用i节点块和数据块,在目录文件中记载了文件和i节点对应关系的管道是有名管道,没有记载的是无名管道。

    管道文件一旦读出,就从管道中删除,所以它具有不可再现性。

  • 相关阅读:
    一个简易的四则运算单元...(15.12.15 BUG更新)
    转一个PDevMode格式属性说明...
    正则表达式语法
    模拟键盘发送文字
    一个修改过简化版的InputQuery
    获取进程列表的单元
    获取EMF文件内全部文字, 并按照左上到右下的顺序排序
    非主窗体在任务栏显示按钮
    禁用窗体关闭按钮
    一个支持FMX.Win框架的托盘控件
  • 原文地址:https://www.cnblogs.com/Lune-Qiu/p/9368051.html
Copyright © 2020-2023  润新知