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 信號)退出。

  本例子中,寫進程退出後,讀進程繼續循環,當再次有寫進程啓動時,讀進程就會再次讀到數據。

相關文章
相關標籤/搜索