APUE FIFO管道

FIFO

参考:http://blog.csdn.net/haomcu/article/details/46647843

   FIFO 表示的是命名管道,可以在两个不相关进程之间进行通信(:未命名管道是pipe)

     FIFO 也表示一种文件类型,可以通过S_ISFIFO(stat结构的st_mode成员的编码)宏来测试文件是否是FIFO类型.    

  创建FIFO

     #include<sys/stat.h>      //mode参数和open函数中的mode参数相同

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

     int mkfifoat(int fd, const char * path, mode_t mode);

mkfifoat和mkfifo类似,不过mkfifoat可以fd表的文件目录下创建一个FIFO,mkfifoat有三种情况:

1.  如果path是绝对路径,则忽略fd,这时和mkfifo相同。

2.  如果path是相对路径fd是一个打开目录的有效文件描述符,。

3.  如果path是相对路径,并且fd有AT_FDCWD标志,则pathname当前工作目录开始(这时与mkfifo类似)

: 

建了一个FIFOopen来打开它,实际上,一般的文件I/O函数(write,read,close,unlink等)都需要FIFO。

POSIX.1的XSI扩展中应用程序可以用接口mknod,mknodat函数来创建FIFO.

open一个FIFO时,非阻塞标志(O_NONBLOCK)会产生下面的影响:

参考: http://blog.csdn.net/erlian_beijing/article/details/46698401

特点一:不指定O_NONBLOCK(即open没有位或O_NONBLOCK)

1、open以只读方式打开FIFO时,要阻塞到某个进程为写而打开此FIFO   FIFO读 阻塞 直到 fifo写打开

2、open以只写方式打开FIFO时,要阻塞到某个进程为读而打开此FIFO   FIFO写 阻塞 直到 fifo读打开

3、open以只读、只写方式打开FIFO时会阻塞,调用read函数从FIFO里读数据时read也会阻塞。(此时读写阻塞)

4、调用write函数向FIFO里写数据,当缓冲区已满write也会阻塞。(写缓冲区慢)

5、通信过程中若写进程先退出了,则调用read函数从FIFO里读数据时不阻塞;若写进程又重新运行,则调用read函数从FIFO里读数据时又恢复阻塞。

6、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到SIGPIPE信号)退出。fifo read 退出导致fifo write 收到SIGPIPE退出

特点二:指定O_NONBLOCK(即open位或O_NONBLOCK)

1、先以只读方式打开:如果没有进程已经为写而打开一个FIFO, 只读open成功,并且open不阻塞。fifo 读,且fifo 写没打开,read 成功返回

2、先以只写方式打开:如果没有进程已经为读而打开一个FIFO,只写open将出错返回-1。fifo 写 则会返回-1

3、read、write读写命名管道中读数据时不阻塞。

4、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到SIGPIPE信号)退出。

5write一个没有无进程为读而打开的FIFO,将产生SIGPIPE信号

 

参考:  http://blog.csdn.net/yefengzhichen/article/details/50262465s

https://www.cnblogs.com/benxintuzi/p/4781779.html

http://blog.csdn.net/yefengzhichen/article/details/50262465

 

Fifo 的用途:

1)   shell命令使用FIFO将数据从一条管道传送到另一条管道,无需创建中间临时文件。

2)  客户进程-服务器进程应用程序中,FIFO用作汇聚点,在客户进程和服务器进程之间传递数据。

实例:考虑这样一个过程,他需要对一个输入文件进行两次处理,示意图如下:


使用FIFO和tee将一个流发送到两个不同的进程:  我们可以使用FIFO和tee命令如下处理: 

mkfifo fifo1          :创建FIFO

prog3 < fifo1 &      :后台运行prog3,并将标准输入重定向为fifo1

prog1 < (输入文件) | tee fifo1 | prog2  :prog1的标准输入重定向到infile,标准输出通过管道连接tee的标准输入,tee程序的参数是fifo1(程序内部可以向

FIFO写),然后tee的标准输出通过管道连接到prog2的标准输入

执行流程如下:

 

2、使用FIFO进行client 进程-server 进程通信

首先看下图,well-known FIFO是server和所有client都知道FIFO的路径名

 

上图如果server要响应client该怎么办呢? 可以:  client发请求的时候顺带发送自己的pid,server根据client pid来创建一个FIFO。

如下图的形式:    专门用来和该client process通信(例如命名为/tmp/serv1.XXXX  XXXX为client pid),

 

这样问题似乎得到了解决,但考虑以下情况:

· client请求完后崩溃了怎么办?那么client-specific FIFO的读端被关闭,所以server写的时候就会返回SIGPIPE信号,server必须处理这种信号。

那么这样看来,这种方法也不尽合理。

还有最后几点要说明的是,

1)FIFO只适用于单机系统;如果在NFS上(网络文件系统,“容许不同客户端及服务端通过一组RPC分享相同的文件系统”),肯定是不行的;

2)上述的简单服务器是“迭代服务器(iterative server)”,也就是server在完全处理完一个client请求后,在处理下一个;另外一种设计是“并发服务器(concurrent server)”,UNIX下常见的one-child-per-client server就是,即为每个客户分配一个进程(或线程);

3)迭代服务器存在的一个问题是DoS(拒绝服务型攻击),如上图,client只发送请求但并不读为自己创建的FIFO,这样会使server阻塞;解决办法是:设阻塞时钟,或改为并发服务器,虽然并发服务器面临大量DoS时也许会因为fork达到上限而无法继续fork,但总比迭代服务器好些。

 

http://blog.csdn.net/to_be_it_1/article/details/28384117

           例: client  与 server  通信程序

             Server 负责创建FIFO1, FIFO2管道,  client 从标准输入中读取文件名 传给server, server 打开文件名,

然后将文件内容写到管道FIFO2,client 读取后打印到终端。

                    Client_main.c:

#include "fifo.h"   

extern client(int, int);  

int main(int argc, char **argv)  

{  

    int     readfd, writefd;  
    writefd = open(FIFO1, O_WRONLY, 0);  
    readfd  = open(FIFO2, O_RDONLY, 0);  
    if(readfd < 0)
    {
       printf("open fail : %d\nerror message: %s\n", errno, strerror(errno));
   }  

    client(readfd, writefd);  
    close(readfd);  
    close(writefd);  

    unlink(FIFO1);  
    unlink(FIFO2);  

  return 0;
}

          Client.c:

            

int client(int readfd, int writefd)  
{  
    size_t  len;  
    ssize_t n;  
    char    buff[MAXLINE];  

    /*read pathname*/  
    fgets(buff, MAXLINE, stdin);  
    len = strlen(buff);  
    if(buff[len-1] == '\n')  
        len--;  

   	/*write pathname to IPC channel*/  
    write(writefd, buff, len);  
    printf("client send:  %s\0", buff);
    	/*read from IPC, write to standard output*/  
    while((n = read(readfd, buff, MAXLINE)) > 0)
    {
   	printf("client recv: %s\n", buff);
       	write(STDOUT_FILENO, buff, n);  
    }

   printf("client exit !\n");
  return 0;
}  

Fifo.h:

#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/wait.h>  
#include <fcntl.h>  
#include <errno.h>  
#define FIFO1   "/tmp/fifo.1"     
#define FIFO2   "/tmp/fifo.2"     
#define MAXLINE 4096  

Server_main.c:

 #include "fifo.h"  
 #include <sys/stat.h>  
 #define FILE_MODE   (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)    

extern void server(int, int);  

int main(int argc, char **argv)  
{  
    int     readfd, writefd;  
    /*creat two FIFOs:OK if they already exist*/  

    if((mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST))
    {  
        printf("can't create %s.\n", FIFO1);  
    }  

    if((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST))
    {  
        unlink(FIFO1);  
        printf("can't create %s.\n", FIFO1);  
    }  

    readfd  = open(FIFO1, O_RDONLY, 0);  
    writefd = open(FIFO2, O_WRONLY, 0);  
    server(readfd, writefd);  

    exit(0);
  //return 0;
}  

Server.c:

#include "fifo.h"  

void server(int readfd, int writefd)  
{  
    int     fd; 
    ssize_t n;
    char    buff[MAXLINE+1];    

    /*read pathname frome IPC channel*/  
    if((n = read(readfd, buff, MAXLINE)) == 0){  
        printf("end-of-file while reading pathname.\n");  
        return ;  
    }

    buff[n] = '\0';         /*null terminate pathname*/  
    printf("server recv: %s\n", buff);

    if((fd = open(buff, O_RDONLY)) < 0)
    {  
        /*error:must tell client*/    
        snprintf(buff+n, sizeof(buff)-n, ":can't open, %s\n", strerror(errno));  
        n = strlen(buff);  
        write(writefd, buff, n);
    }else
    {  
        /*open succeeded:copy file to IPC channel*/   
        while((n = read(fd, buff, MAXLINE)) > 0)
        {
           if( write(writefd, buff, n) < 0)
           {
               printf("send error : %d\nerror message: %s\n", errno, strerror(errno));
           }   
          printf("server write---%d--: %s\n", n, buff);
        }
     }  

    close(fd);
}  

执行:

Client:

   

Server:

       

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值