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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM