zoukankan      html  css  js  c++  java
  • linux有名管道fifo,进程间通信

    命名管道(FIFO)不同于无名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。

    命名管道(FIFO)和无名管道(pipe)有一些特点是相同的,不一样的地方在于:

    1、FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存中。

    2、当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。

    3、FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。


    int mkfifo(const char *pathname, mode_t mode);用于创建一个管道


    int open(const char *pathname, int flags);用于打开一个管道

    打开FIFO文件和普通文件的区别有2点:

    第一个是不能以O_RDWR模式打开FIFO文件进行读写操作。这样做的行为是未定义的。

    因为我们通常使用FIFO只是为了单向传递数据,所以没有必要使用这个模式。

    如果确实需要在程序之间双向传递数据,最好使用一对FIFO或管道,一个方向使用一个。或者采用先关闭在重新打开FIFO的方法来明确改变数据流的方向。

    第二是对标志位的O_NONBLOCK选项的用法。

    使用这个选项不仅改变open调用的处理方式,还会改变对这次open调用返回的文件描述符进行的读写请求的处理方式。

    O_RDONLY、O_WRONLY和O_NONBLOCK标志共有四种合法的组合方式:

    • flags=O_RDONLY:open将会调用阻塞,除非有另外一个进程以写的方式打开同一个FIFO,否则一直等待。
    • flags=O_WRONLY:open将会调用阻塞,除非有另外一个进程以读的方式打开同一个FIFO,否则一直等待。
    • flags=O_RDONLY|O_NONBLOCK:如果此时没有其他进程以写的方式打开FIFO,此时open也会成功返回,此时FIFO被读打开,而不会返回错误。
    • flags=O_WRONLY|O_NONBLOCK:立即返回,如果此时没有其他进程以读的方式打开,open会失败打开,此时FIFO没有被打开,返回-1。

    open函数调用中的参数标志O_NONBLOCK会影响FIFO的读写操作。

    规则如下:

    • 对一个空的阻塞的FIFO的read调用将等待,直到有数据可以读的时候才继续执行/
    • 对一个空的非阻塞的FIFO的read调用立即返回0字节。
    • 对一个完全阻塞的FIFO的write调用将等待,直到数据可以被写入时才开始执行。
      • 系统规定:如果写入的数据长度小于等于PIPE_BUF字节,那么或者写入全部字节,要么一个字节都不写入。

    注意这个限制的作用:
    当只使用一个FIF并允许多个不同的程序向一个FIFO读进程发送请求的时候,为了保证来自不同程序的数据块 不相互交错,即每个操作都原子化,这个限制就很重要了。如果能够包子所有的写请求是发往一个阻塞的FIFO的,并且每个写请求的数据长父小于等于PIPE_BUF字节,系统就可以确保数据绝不会交错在一起。通常将每次通过FIFO传递的数据长度限制为PIPE_BUF是一个好办法。

    • 在非阻塞的write调用情况下,如果FIFO 不能接收所有写入的数据,将按照下面的规则进行:
      • 请求写入的数据的长度小于PIPE_BUF字节,调用失败,数据不能被写入。
      • 请求写入的数据的长度大于PIPE_BUF字节,将写入部分数据,返回实际写入的字节数,返回值也可能是0。

    其中。PIPE_BUF是FIFO的长度,它在头文件limits.h中被定义。在linux或其他类UNIX系统中,它的值通常是4096字节。

    上面都是网上找的资料,有时间再整理吧,下面是自己写的一个测试代码:

    write.c

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    #define FIFO_NAME "/tmp/myfifo"
    int main(){
    	if(access(FIFO_NAME,F_OK) != 0){//如果文件存在
    		int err = mkfifo(FIFO_NAME,0777);
    		if(err != 0){
    			perror("Create fifo failed");
    			return -1;
    		}
    	}
    	printf("create fifo succeed!
    ");
    	int fifo_fd = open(FIFO_NAME,O_WRONLY);
    	printf("open fifo succeed!
    ");
    	if(fifo_fd < 0){
    		printf("open fifo failed!
    ");
    		return -1;
    	}
    	int i = 1;
    	for(;i < 100; i++){
    		if(write(fifo_fd,&i,sizeof(int)) != -1)
    			sleep(1);
    		else
    			perror("Write failed");
    	}
    	printf("write succeed: %d
    ",i);
    	close(fifo_fd);
    	return 0;
    	
    }
    

      

    read.c

    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define FIFO_NAME "/tmp/myfifo"
    int main(){
    	int fifo_fd = open(FIFO_NAME,O_RDONLY | O_NONBLOCK ); 
    	if(fifo_fd < 0){
    		printf("open fifo failed!
    ");
    		return -1;
    	}
    	int i;
    	sleep(5);
    	while(1){
    		int size = read(fifo_fd,&i,sizeof(int));
    		if(size > 0)
    			printf("读到:%d
    ",i);
    	}
    	close(fifo_fd);
    	return 0;
    	
    }
    

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

      本例子中,写进程退出后,读进程继续循环,当再次有写进程启动时,读进程就会再次读到数据。

  • 相关阅读:
    Hunspell介绍及试用
    语音活性检测器py-webrtcvad安装使用
    Nginx处理请求的11个阶段(agentzh的Nginx 教程学习记录)
    搭建rsync服务并同步重要数据
    语料库基础学习
    解决SSH远程执行命令找不到环境变量的问题
    Centos7上安装、破解bamboo6.0.3
    Java代码走查具体考察点
    Bamboo基础概念
    安装OpenResty开发环境
  • 原文地址:https://www.cnblogs.com/qingergege/p/9489682.html
Copyright © 2011-2022 走看看