linux 进程间通信之FIFO[亲测有效]

linux 进程间通信之FIFO[亲测有效]FIFO与管道几乎类似,所以FIFO也是一个字节流,从FIFO读取的顺序也是与被写入FIFO的顺序一致,容量是也有限的,也是可以确保写入不超过PIPE_BUF字节的操作是原子的,FIFO的本质也是一个管道,但传递方向是可以双向的,它们两者之间的最大差别在于FIFO在文件系统中拥…

1.概述

FIFO与管道几乎类似,所以FIFO也是一个字节流,从FIFO读取的顺序也是与被写入FIFO的顺序一致,容量是也有限的,也是可以确保写入不超过PIPE_BUF字节的操作是原子的,FIFO的本质也是一个管道,但传递方向是可以双向的,它们两者之间的最大差别在于FIFO在文件系统中拥有一个名称,并且打开方式与打开一个普通文件是一样的(使用open),这样就能够将FIFO用于非相关进程之间的通信(如客户端和服务器)。(不熟悉管道的可以看我的另一篇文章讲述管道linux 进程间通信之管道)

2.创建FIFO

#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);//return 0 on success,or -1 on error
  • mode 参数指定了新FIFO的权限即文件权限(rw-rw—-)
  • mode 参数会与进程中的umask值进行异或来指定最终的权限数值(所以一般设置umask(0))

3.打开FIFO

  • FIFO被创建成功,任何进程都能够打开它,只要它能够通过常规的文件权限检测即最初设置的mode。
readFd=open(pathname,O_RDONLY);//打开只读方式

writeFd=open(pathname,O_WRONLY);//打开只写方式
  • 打开一个FIFO以便读取数据(open() O_RDONLY标记)将会阻塞直到另一个进程打开FIFO以写入数据(open() O_WRONLY)为止。相应地,打开一个FIFO以写如数据将会堵塞知道另一个进程打开FIFO以读取数据为止。

4.使用FIFO唯一明智的做法是在两端分别设置一个读取进程和一个写入进程的原因

  • 可以确保每次写入不超过PIPE_BUF字节的操作是原子的,当超过PIPE_BUF字节,内核会对消息进行拆分,那么就有可能混淆与其他写者发送的消息,如果只有一个写者则不用担心混淆即可以忽略这个限制。

  • 多个客户端从FIFO中读取数据时会相互竞争,这样就可能会出某个客户端读取到其他客户端的响应消息。

  • 在单服务器、多客户端应用程序中使用FIFO

    linux 进程间通信之FIFO[亲测有效]

服务端程序核心

// we get the permissions we want
    umask(0);
    if(mkfifo(SERVER_FIFO,S_IRUSR|S_IWUSR|S_IWGRP)==-1&&errno!=EEXIST){
        ERR_EXIT("mkfifo");
    }
    serveFd=open(SERVER_FIFO,O_RDONLY);
    if(serveFd==-1){
        ERR_EXIT("open");
    }

for(;;){
        //Read requests and send responses
        if (read(serveFd, &req, sizeof(struct request)) != sizeof(struct request)) {
                errMsg("ERROR reading request;discarding\n");
                continue;
        }
        //Open client FIFO (previously created by client)
        snprintf(clientFifo,CLIENT_FIFO_NAME_LEN,CLIENT_FIFO_TEMPLATE,(long)req.pid);
        clientFd=open(clientFifo,O_WRONLY);
        if(clientFd==-1){
           errMsg("open\n");
            continue;
        }
        
        //send response and close FIFO
        if(write(clientFd,&resp, sizeof(struct response))!= sizeof(struct response)){
            errMsg("Error writing to FIFO");
        }
        if(close(clientFd)==-1){
            errMsg("close");
        }
      
    }

客户端程序核心

    //create our FIFO (before sending request,to avoid a race)
    umask(0);
    snprintf(clientFifo,CLIENT_FIFO_NAME_LEN,CLIENT_FIFO_TEMPLATE,(long)getpid());
    if(mkfifo(clientFifo,S_IRUSR|S_IWUSR|S_IWGRP)==-1&&errno!=EEXIST){
        ERR_EXIT("mkfifo");
    }
    serverFd=open(SERVER_FIFO,O_WRONLY);    
    if(serverFd==-1){
        ERR_EXIT("open");
    }   
    if (write(serverFd, &req, sizeof(struct request)) != sizeof(struct request)) {
            ERR_EXIT("write");
    }
    //open our FIFO,read and display response
    clientFd=open(clientFifo,O_RDONLY);
    if(clientFd==-1){
        ERR_EXIT("open");
    }
    if(read(clientFd,&resp, sizeof(struct response))!= sizeof(response)){
        ERR_EXIT("read");
    }
    if(close(clientFd)==-1){
        ERR_EXIT("close");
    }

5.非阻塞I/O

当一个进程打开一个FIFO的一端时,如果FIFO的另一端还没有被打开,则该进程会被阻塞。但有些时候阻塞并不是期望的行为,可以通过调用open()时指定O_NONBLOCK

fd=open("fifopath",O_RDONLY|O_NONBLOCK);
if(fd==-1){
    errExit("open");
}

linux 进程间通信之FIFO[亲测有效]

5.1 打开一个FIFO时使用O_NONBLOCK标记存在两个目的

  • 它允许单个进程打开一个FIFO的两端。这个进程首先会在打开FIFO时指定O_NONBLOCK标记以便读取数据,接着打开FIFO以便写入数据。
  • 它防止打开两个FIFO的进程之间产生死锁。
linux 进程间通信之FIFO[亲测有效]

打开两个FIFO的进程之间的死锁

5.2 非阻塞read()和write()

  • O_NONBLOCK 标记不仅会影响open()的语义,还会影响后续的read()和write()调用语义。

  • 可以通过fcntl() 启用或禁用打开着的文件的O_NONBLOCK状态的标记。

启用标记

int flags;
flags=fcntl(fd,F_GETFL);//Fetch open files status flags
flags|=O_NONBLOCK; // Enable O_NONBLOCK bit
fcntl(fd,F_SETFL,flags);// Update open files status flags

禁用标记

flags=fcntl(fd,F_GETFL);
flags&=~O_NONBLOCK; //disable O_NONBLOCK bit
fcntl(fd,F_SETFL,flags);

6.管道和FIFO中read和write的语义

从一个包含p字节的管道或FIFO中读取n字节的语义

linux 进程间通信之FIFO[亲测有效]

向一个管道或FIFO写入n字节的语义

linux 进程间通信之FIFO[亲测有效]

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13895.html

(0)

相关推荐

  • Python实现访问数据库的API接口设计

    Python实现访问数据库的API接口设计SQLAlchemy是一个Python SQL工具和对象关系映射器(ORM),可以方便地实现访问数据库的API接口,适用于多种关系型数据库。它提供了一种简单的方式来定义数据模型,并将其映射到数据库模式。相比于直接使用SQL语句,SQLAlchemy可以轻松地修改数据库模型而不用修改SQL语句。此外,SQLAlchemy还提供了一些高级功能,例如连接池、事务、数据库迁移等,使得访问数据库变得更加方便和可靠。

    2023-12-05
    68
  • MySql5.7 datetime 默认值为‘0000-00

    MySql5.7 datetime 默认值为‘0000-00注: NO_ZERO_IN_DATE:在严格模式下,不允许日期和月份为零 NO_ZERO_DATE:设置该值,MySql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。

    2023-02-01
    131
  • SQLDataException: Unsupported conversion from LONG to java.sql.Timestamp

    SQLDataException: Unsupported conversion from LONG to java.sql.Timestamp可参考:https://blog.csdn.net/weixin_38067745/article/details/105287980 在用mybatisplus中,可以用lombok的@NoArg…

    2023-03-14
    111
  • 大数据Hadoop之——Flink Table API 和 SQL(单机Kafka)「终于解决」

    大数据Hadoop之——Flink Table API 和 SQL(单机Kafka)「终于解决」一、Table API 和 Flink SQL 是什么 Table API 和 SQL 集成在同一套 API 中。 这套 API 的核心概念是Table,用作查询的输入和输出,这套 API 都是批处理

    2023-05-15
    85
  • Python Basic Function: 帮助你更轻松地处理数据和完成任务

    Python Basic Function: 帮助你更轻松地处理数据和完成任务Python是一种非常流行和广泛使用的编程语言,不仅可以用于Web开发、人工智能和大数据处理等领域,还可以用于一般的数据处理和常规任务。而Python的基本函数就是Python最重要的组成部分之一,它们可以帮助你更轻松地处理数据和完成任务。在这篇文章中,我们将探讨一些基础的Python函数,以及如何使用它们来解决具体问题。

    2024-03-14
    30
  • 使用 StatsD + Grafana + InfluxDB 搭建 Node.js 监控系统

    使用 StatsD + Grafana + InfluxDB 搭建 Node.js 监控系统之前使用 ELK 搭了一套监控图表,由于一些原因,比如: Kibana 经常查日志查挂 Kibana 的图表不太美观、不够灵活 所以调研了一下,选择用 StatsD + Grafana + InfluxDB 搭建一套新的监控系统。

    2023-07-30
    79
  • mysql5.7 varchar最大长度_varchar一个字符多少字节

    mysql5.7 varchar最大长度_varchar一个字符多少字节今天在看《MySQL必知必会》上面写 varchar(),最大是255,但是实际用的时候经常定到2000。因此查阅了下,这本书使用的MySQL版本是5.0,因此确实最大是255 mysql5.0版本…

    2023-03-14
    95
  • Python os.path.filename实现文件路径获取文件名

    Python os.path.filename实现文件路径获取文件名在Python编程中,经常需要操作文件。而文件操作中,获取文件名是很常见的需求。Python的os.path模块提供了一系列函数,可以帮助我们实现获取文件名的操作。其中,os.path.filename()函数是专门用于获取文件名的函数。本文将着重介绍该函数及其用法。

    2024-02-29
    46

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注