linux進程通信之命名管道

前一節學習了無名管道,這節學習命名管道。

二命名管道
無名管道只能用來在父子進程或兄弟進程之間進行通信,這就給沒有親緣關係的進程之間數據的交換帶來了麻煩,解決這個問題就是本節要學習的另一種管道通信:命名管道。
命名管道也被稱爲FIFO文件,FIFO不同於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即使與FIFO的創建進程不存在親緣關係的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進程以及FIFO的創建進程之間),因此,通過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操作。

http://blog.csdn.net/xiaoliangsky/article/details/40121893

1 mkfifo
int mkfifo(const char *pathname, mode_t mode);
mafifo函數創建一個FIFO,FIFO在文件系統中表現爲一個文件。
pahtname 文件路徑
mode 和系統調用open函數中的mode是一樣的。

返回值
如果函數調用成功返回非-1;
函數調用失敗返回-1。

2 命名管道操作
FIFO在文件系統中表現爲一個文件,大部分的系統文件調用都可以用在FIFO上面,比如:read,open,write,close,unlink,stat等函數。但是seek等函數不能對FIFO調用。

2.1 打開命名管道
可以調用open函數打開命名管道,但是有兩點要注意
1)不能以O_RDWR模式打開命名管道FIFO文件,否則其行爲是未定義的,管道是單向的,不能同時讀寫;
2)就是傳遞給open調用的是FIFO的路徑名,而不是正常的文件

打開FIFO文件通常有四種方式:
open(pathname, O_RDONLY);//1只讀、阻塞模式
open(pathname, O_RDONLY | O_NONBLOCK);//2只讀、非阻塞模式
open(pathname, O_WRONLY);//3只寫、阻塞模式
open(pathname, O_WRONLY | O_NONBLOCK);//只寫、非阻塞模式

注意阻塞模式open打開FIFO:
1)當以阻塞、只讀模式打開FIFO文件時,將會阻塞,直到其他進程以寫方式打開訪問文件;
2)當以阻塞、只寫模式打開FIFO文件時,將會阻塞,直到其他進程以讀方式打開文件;
3)當以非阻塞方式(指定O_NONBLOCK)方式只讀打開FIFO的時候,則立即返回。當只寫open時,如果沒有進程爲讀打開FIFO,則返回-1,其errno是ENXIO。
下面是一個命名管道的例子:

用命名管道實現多個進程間的通信,一個server進程負責接受多個cilent進程發來的消息

server.c代碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/stat.h>

typedef struct 
{
	pid_t     child_pid;
	char      message[PIPE_BUF+1];
}fifo_message;

int main()
{
	int                     fd;
	const char             *fifoname;
	fifo_message            msgbuf;

	fifoname = "/tmp/serverfifo";

	if (access(fifoname, F_OK) == -1)
	{
		if (mkfifo(fifoname, 0666) == -1)
		{
			perror("mkfifo error\n");
			exit(-1);
		}
	}

	if ((fd = open(fifoname, O_RDONLY)) == -1)//以只讀、阻塞模式打開
	{
		fprintf(stdout, "open %s failed\n", fifoname);
		exit(-1);
	}

	while (1)
	{
		if (read(fd, &msgbuf, sizeof(msgbuf)) < 0)
		{
			close(fd);
			perror("read error\n");
			exit(-1);
		}

		fprintf(stdout, "message from child: %d, message: %s\n", msgbuf.child_pid, msgbuf.message);
		sleep(1);
	}
    
	return 0;
}

client.c的代碼:

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

struct fifo_message
{
	pid_t      child_pid;
	char       message[PIPE_BUF+1];
};


int main()
{
	int                     fd;
	const char             *fifoname;
	struct fifo_message     msgbuf;

	fifoname = "/tmp/serverfifo";
	if (access(fifoname, F_OK) == -1)
	{
		perror("access error\n");
		exit(-1);
	}

	if ((fd = open(fifoname, O_WRONLY)) < 0)//以只寫、阻塞模式打開
	{
		perror("open error\n");
	}

	msgbuf.child_pid = getpid();

	while (1)
	{
		printf("input the message: ");
		if (fgets(msgbuf.message, sizeof(msgbuf.message), stdin) == NULL)
		{
			perror("fgets error or end\n");
			break;
		}

		msgbuf.message[strlen(msgbuf.message)] = '\0';

		if (write(fd, &msgbuf, sizeof(msgbuf)) == -1)
		{
			perror("write error\n");
			close(fd);
			exit(-1);
		}
	}
	
	close(fd);

	return 0;
}

運行結果:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章