linux有名管道fifo,进程间通讯

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

 

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

 

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

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

三、FIFO 有名字,不相关的进程能够经过打开命名管道进行通讯。blog

 


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


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

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

 

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

由于咱们一般使用FIFO只是为了单向传递数据,因此没有必要使用这个模式。pip

若是确实须要在程序之间双向传递数据,最好使用一对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!\n");
	int fifo_fd = open(FIFO_NAME,O_WRONLY);
	printf("open fifo succeed!\n");
	if(fifo_fd < 0){
		printf("open fifo failed!\n");
		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\n",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!\n");
		return -1;
	}
	int i;
	sleep(5);
	while(1){
		int size = read(fifo_fd,&i,sizeof(int));
		if(size > 0)
			printf("读到:%d\n",i);
	}
	close(fifo_fd);
	return 0;
	
}

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

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

相关文章
相关标签/搜索