进程间通信------FIFO

   通常所说的管道是指无名管道,管道最大的劣势为:只能用于有亲缘关系的各个进程间的通信,所以使管道有一定的局限性.而FIFO就是来解决管道没有亲缘关系的各个进程间的通信

     每个FIFO都有一个路径与之相关联,从而允许无亲缘关系的进程间通信.

     FIFO相关的函数:

   #include<sys/types.h>

           #include<sys/stat.h>

          int mkfifo(const char* pathname,mode_t mode);     //错误返回-1

    此函数的作用为:使pathname与所创建的FIFO相关联,打开FIFO就用open函数打开路径pathname

   FIFO的读写就是通过open函数返回的文件描述来操作

    


    管道和FIFO需要注意的地方就是它们分别在什么地方阻塞


FIFO的阻塞
当前操作管道或FIFO的现有操作阻塞返回(默认)设置O_NONBLOCK返回
open FIFO 只读FIFO打开来写成功返回成功返回
 FIFO不是打开来写阻塞到FIFO打开来写成功返回
open FIFO 只写FIFO打开读成功返回成功返回
 FIFO不是打开来读阻塞到FIFO打开来读返回ENXIO错误
从空管道或FIFO read管道或FIFO打开来写阻塞到管道或FIFO中有数据或者管道或FIFO
不再为写打开着为止
返回EAGAIN错误
 管道或FIFO不是打开来写read 返回0(文件结束符)read 返回0(文件结束符)
往管道或FIFO write管道或FIFO打开来读分情况分情况
 管道或FIFO不是打开来读给线程产生SIGPIPE给线程产生SIGPIPE


注意上面表格中当管道或FIFO已有一端打开读时,此时往管道或FIFO中写入数据时,存在如下限制:

1,如果请求写入的数据的字节数小于或等于PIPE_BUF,则写入操作是原子的,不存在两个进程同时写.

但当大于PIPE_BUF时,就不能保证原子性,可能存在交叉写的可能.

2,如果待写入的字节数小于PIPE_BUF,要写入的数据在管道中还有足够的空间存放,则所有数据都写入

3,如果待写入的字节数小于PIPE_BUF,该管道或FIFO中没有足够的空间存放要写入的数据,则立即返回EAGAIN

4,如果待写入的字节数大于PIPE_BUF,且管道或FIFO中还有剩余空间,则只写入部分数据,使管道或FIFO写满.

5,如果待写入的字节数大于PIPE_BUF,且管道或FIFO已满,则返回EAGAIN

6,如果向一个没有为读打开着的管道或FIFO写入,那么内核将产生一个SIGPIPE信号

  a)如果调用进程没有捕获也没有忽略该信号,默认就是终止该进程

  b)如果调用进程忽略该信号或者捕获了该信号并从其信号处理程序中返回,那么write返回一个EPIPE错误.


一下是利用FIFO写的服务器端和客户端代码:

服务器端:FIFO_server.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_SERVER "fifo.server"
#define FIFO_CLIENT "fifo.client"
#define MAXLINE 512

int main(int argc,char *argv[])
{
     int fd_read;
    int fd_write;
    int fd_dump;
    int res;
    int fd;
    char buf[MAXLINE+1];
    memset(buf, '\0', sizeof(buf));
    //验证有名管道文件存不存在
    if (access(FIFO_SERVER, F_OK) == -1)
   {
       printf("创建有名管道FIFO:\n");
        res = mkfifo(FIFO_SERVER, 0766);
        if (res != 0)
    {
            fprintf(stderr, "Could not create fifo %s\n", FIFO_SERVER);
            exit(EXIT_FAILURE);
        }
    }

    printf("Process %d opening FIFO O_WRONLY\n", getpid());
    fd_read = open(FIFO_SERVER,O_RDONLY);                               //以读方式打开管道
    fd_dump = open(FIFO_SERVER, O_WRONLY);                           //以写方式打开管道
    printf("the file's descriptor is %d\n", fd_read);
    int n = 0;
    
    while((n = read(fd_read,buf,MAXLINE)) > 0)
    {
      /*
        if(buf[n-1] == '\n')
            n--;
        buf[n] = '\0'
        */
        //打开从管道中读出来的文件路径
        printf("从管道中读到%d字节数据:%s\n",n,buf);
        if((fd_write = open(FIFO_CLIENT,O_WRONLY)) < 0)
        {
            printf("不能打开客户端的FIFO文件!\n");
            continue;
        }
        printf("打开文件读取数据:\n");
        if((fd = open(buf,O_RDONLY)) < 0)    //打开错误就将错误信息写入到客户端管道
        {
            snprintf(buf+n,sizeof(buf) - n,": 不能打开!,%s\n",strerror(errno));
            n = strlen(buf);
            write(fd_write,buf,n);
            close(fd_write);
        }
        else
        {
            memset(buf, '\0', sizeof(buf));
            
            while((n = read(fd,buf,MAXLINE)) > 0)
            {
                write(fd_write,buf,n);
            }
            printf("将文件的数据读完,且全部写入管道!\n");
            close(fd);
            close(fd_write);
        }
    }
    unlink(FIFO_SERVER);
    printf("Process %d finished\n", getpid());
    exit(EXIT_SUCCESS);
 }


客户端:FIFO_client.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_SERVER "fifo.server"
#define FIFO_CLIENT "fifo.client"
#define MAXLINE 512

int main(int argc,char *argv[])
{
    int fd_read;
    int fd_write;
    int res;
    char buf[MAXLINE+1];

    memset(buf, '\0', sizeof(buf));
      //验证有名管道文件存不存在
    if (access(FIFO_CLIENT, F_OK) == -1)
   {
       printf("创建有名管道FIFO:\n");
        res = mkfifo(FIFO_CLIENT, 0766);
        if (res != 0)
    {
            fprintf(stderr, "Could not create fifo %s\n", FIFO_CLIENT);
            exit(EXIT_FAILURE);
        }
    }
   
    printf("Process %d opening FIFO O_RDONLY\n", getpid());
    fd_write = open(FIFO_SERVER,O_WRONLY);     //以只写的方式打开服务器端的FIFO
   res = write(fd_write,argv[1],strlen(argv[1]));
   printf("读出的文件路径大小为:%d\n",res);
    if(res  != strlen(argv[1]))            //将文件路径写入到服务器端管道
    {
        printf("将文件路径写入服务器端FIFO失败!\n");
        unlink(FIFO_CLIENT);
        exit(EXIT_FAILURE);
    }
 
    fd_read = open(FIFO_CLIENT, O_RDONLY);                       //用读方式打开客户端管道
    printf("the file's descriptor is %d\n",fd_read);

    int n;
    while( (n = read(fd_read, buf, MAXLINE)) > 0)          //从管道中读出数据
    {
         // printf("从管道中读出的数据大小为:%d\n",n);
           write(STDOUT_FILENO,buf,n);
           memset(buf, '\0', sizeof(buf));
     }
            
    close(fd_read);
    unlink(FIFO_CLIENT);
    printf("Process %d finished\n", getpid());
    exit(EXIT_SUCCESS);
}


测试用的文件:test

sdfhidhsfuh
fjdsihjfidsh
243254
fjdsi13213


输出结果:

首先运行服务器端:

[tsj@********* ch09 16:30]$gcc -o FIFO_server FIFO_server.c
[tsj@********* ch09 16:31]$./FIFO_server
创建有名管道FIFO:
Process 24940 opening FIFO O_WRONLY
the file's descriptor is 3
从管道中读到4字节数据:test
打开文件读取数据:
将文件的数据读完,且全部写入管道!

客户端:

[tsj@********* ch09 16:31]$gcc -o FIFO_client FIFO_client.c
[tsj@********* ch09 16:31]$./FIFO_client test
创建有名管道FIFO:
Process 25120 opening FIFO O_RDONLY
读出的文件路径大小为:4
the file's descriptor is 4
sdfhidhsfuh
fjdsihjfidsh
243254
fjdsi13213
Process 25120 finished
[tsj@********* ch09 16:31]$



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值