【IPC通訊】有名管道FIFO

前面學習過(匿名)管道(見前面博客),匿名管道只能用於有親緣關係的各個進程之間,爲了解決這個限制,UNIX系統進而引入了FIFO,也稱爲有名管道(named pipe)。shell

FIFO(first in, first out),是一個半雙工數據流,也即一個半雙工管道。不一樣於匿名管道的是,每一個FIFO有一個路徑名(或文件名)與之關聯,也即FIFO的名字。有了名字,無親緣關係的進程間就能夠經過管道進行數據傳輸了。app

建立FIFO的方式:函數

  • 使用shell命令 mkfifo建立一個有名管道
  • 使用C庫函數mkfifo建立一個有名管道

使用shell命令 mkfifo建立一個有名管道學習

[infor@s123 FIFO]$ mkfifo npipe
[infor@s123 FIFO]$ ls -l
prw-r--r--  1 infor app 0 Nov 13 11:32 npipe

上面咱們建立了一個有名管道npipe,咱們能夠看到有名管道實際上是一個文件,文件類型是「p」,管道類型。

咱們在開啓兩個終端,分別爲A和B。在A終端下將數據寫入管道,在B終端下將數據讀出來。spa

[infor@s123 FIFO]$ ping 10.4.123.124 >> npipe
#會阻塞在這裏,等待另外一個進程讀

在終端A下將ping的結果寫入管道npipe,這裏會一直阻塞到另外一個進程將數據所有讀出或停止讀出。code

[infor@s123 FIFO]$ cat npipe
PING 10.4.123.124 (10.4.123.124) 56(84) bytes of data.
64 bytes from 10.4.123.124: icmp_seq=0 ttl=128 time=0.838 ms
64 bytes from 10.4.123.124: icmp_seq=1 ttl=128 time=0.835 ms
64 bytes from 10.4.123.124: icmp_seq=2 ttl=128 time=0.843 ms
64 bytes from 10.4.123.124: icmp_seq=3 ttl=128 time=0.834 ms

在終端B下讀取npipe。

使用C庫函數mkfifo建立一個有名管道進程

#include <sys/types.h>
#include <sys/stat.h>
/*
函數說明:依參數pathname創建特殊的FIFO文件,該文件必須不存在,而參數mode爲該文件的權限
返回值:若成功則返回0,不然返回-1,錯誤緣由存於errno中
*/
int mkfifo(const char *pathname, mode_t mode);

 對於建立方式,mkfifo隱含指定O_CREAT|O_EXCL,也即mkfifo建立一個新的FIFO,若是該FIFO已經存在,則會返回EEXIST錯誤。ip

對於參數mode可有以下選項:
S_IRUSR:當前用戶可讀
S_IWUSR:當前用戶可寫
S_IRGRP:組成員可讀
S_IWGRP:組成員可寫
S_IROTH:其餘用戶可讀
S_IWOTH:其餘用戶可寫博客

下面經過例子看下如何使用。it

假若有這樣一個案例。進程A執行完將執行結果寫入管道,等待進程B將該結果讀出。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define FIFO_NAME ("/tmp/fifo.1") // 設定FIFO的名字
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 設定建立FIFO的權限

/*建立一個FIFO,等待另外一個進程讀取*/
int main()
{
	int writefd;
	char status[] = "success";
	size_t n = 0;

	// 建立FIFO
	if(mkfifo(FIFO_NAME, FILE_MODE) < 0)
	{
		if(EEXIST == errno)
		{
			printf("FIFO:%s已經存在,不能從新建立\r\n", FIFO_NAME);
		}
		else
		{
			perror("建立FIFO錯誤");
			exit(1);
		}
	}

	// 打開FIFO
	writefd = open(FIFO_NAME, O_WRONLY, 0);
	if(-1 == writefd)
	{
		perror("打開FIFO失敗");
		unlink(FIFO_NAME);
		exit(1);
	}

	// 寫入執行狀態
	n = write(writefd, status, strlen(status));
	if(n != strlen(status))
	{
		perror("寫入FIFO失敗");
		unlink(FIFO_NAME);
		exit(1);
	}

	if(-1 == close(writefd))
	{
		perror("關閉FIFO失敗");
		unlink(FIFO_NAME);
		exit(1);
	}

	return 0;
}

編譯並執行:

[infor@s123 FIFO]$ gcc -o wnpipe wnpipe.c
[infor@s123 FIFO]$ ./wnpipe
#阻塞在這裏等待另一個進程讀取FIFO

這裏咱們看一下/tmp/fifo.1 是否生成:

[infor@s123 tmp]$ ls -l /tmp/fifo.1
prw-r--r--  1 infor app 0 Nov 13 12:58 /tmp/fifo.1

咱們看到FIFO文件已經生成。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define FIFO_NAME ("/tmp/fifo.1") // 設定FIFO的名字
#define MAXLINE (1024)

/*讀取FIFO內容*/
int main()
{
	int readfd;
	char status[MAXLINE];
	size_t n = 0;

	// 打開FIFO
	readfd = open(FIFO_NAME, O_RDONLY, 0);
	if(-1 == readfd)
	{
		perror("打開FIFO失敗");
		unlink(FIFO_NAME);
		exit(1);
	}

	// 讀取FIFO
	n = read(readfd, status, MAXLINE);
	if(-1 == n)
	{
		perror("讀取FIFO失敗");
		exit(1);
	}

	printf("管道內容:%s\r\n", status);

	// 關閉FIFO
	if(-1 == close(readfd))
	{
		perror("關閉FIFO失敗");
		unlink(FIFO_NAME);
		exit(1);
	}

	// 刪除FIFO
	unlink(FIFO_NAME);

	return 0;
}

編譯並執行:

[infor@s123 FIFO]$ gcc -o rnpipe rnpipe.c 
[infor@s123 FIFO]$ ./rnpipe 
管道內容:success

這裏咱們再看一下/tmp/fifo.1 是否還存在:

[infor@s123 tmp]$ ls -l /tmp/fifo.1
ls: /tmp/fifo.1: No such file or directory

能夠看到文件已被刪除了。

 

2011-11-13 任洪彩 qdurenhongcai@163.com

轉載請註明出處。

相關文章
相關標籤/搜索