進程間通信——管道

管道有兩種:無名管道和有名管道。管道是半雙工通訊。管道只在內存上開闢空間,不會在磁盤上開闢空間。

半雙工通訊指數據可以沿兩個方向傳送,但同一時刻只能有一個方向的傳送


先來說說無名管道吧:

無名管道是由調用pipe函數創建的;函數原型如下:

#include <unistd.h> //頭文件

int pipe(int filedes[2]);//函數原型     

返回值:成功返回0,出錯返回-1

參數filedes返回兩個文件描述符:filedes[0]爲讀而打開,filedes[1]爲寫而打開


無名管道它們只能在具有公共祖先的進程之間使用。通常,一個管道由一個進程創建,然後該進程調用fork,此後父、子進程之間就可以應用該管道。


調用fork之後做什麼取決於我們想要有的數據流的方向。對於從父進程到子進程的管道,則父進程應關閉管道的讀端(fd[0]),

子進程則關閉寫端(fd[1]).對於從子進程到父進程的管道,則與之相反。


下面我們用代碼來簡單實現無名管道:

void main()
{
	int fd[2];
	pipe(fd);//創建無名管道,並且將fd[0]綁定爲讀,fd[1]綁定爲寫
	pid_t pid = fork(); //創建子進程
	assert(pid != -1);
	
	//這是從子進程到父進程的管道
	if(pid == 0)
	{
		close(fd[0]); //子進程關閉讀端
		while(1)
		{
			printf("please input data: ");  
			fflush(stdout);
			char buff[128] = {0};
			fgets(buff, 128, stdin);   //輸入數據到buff中
			buff[strlen(buff) - 1] = 0;
			if(strcmp(buff, "end") == 0) //以‘end’結束
			{
				break;
			}
			write(fd[1], buff, strlen(buff));  //將buff中的數據寫入到管道中
		}
		close(fd[1]);  //寫完關閉寫端
	}
	else
	{
		close(fd[1]); //父進程關閉寫端
		while(1)
		{
			char buff[128] = {0};
			int n = read(fd[0], buff, 127); //從管道讀端讀取數據,讀到buff中
			if(n == 0)
			{
				break;
			}
			
			//打開一個文件a.txt,沒有的話在當前路徑下創建
			int fda = open("a.txt", O_WRONLY | O_CREAT | O_APPEND, 0664); 

			assert(fda != -1);
			write(fda, buff, n); //將buff中的數據寫到a.txt中
			close(fda);//關閉文件
		}
		close(fd[0]); //讀完關閉管道的讀端
	}
}


接下來我們看看有名管道(FIFO):

FIFO,管道只能由相關進程使用,這些相關進程的共同的祖先進程創建了管道。但是,通過FIFO,不相關的進程也能交換數據。

FIFO是一種文件類型。創建FIFO類似創建文件。

#include <sys/stat.h>

int mkfifo(const char *pathname,mode_t mode);

返回值,成功則返回0,出錯返回-1;

pathname:是創建的文件名字

mode:創建新文件時使用,eg:O_APPEND,O_CREAT (這個和open函數第三個參數一樣,具體見open參數)。

如果已經用mkfifo創建了一個FIFO,就可用open打開它。


當打開一個FIFO時,非阻塞標誌(O_NONBLOCK)會產生下列影響。

沒有指定O_NONBLOCK:open使用時會阻塞運行:如果只有只讀打開或者只寫打開的時候,open函數會阻塞,直到另一個進程以另一種方式打開此文件。

指定了O_NONBLOCK,則只讀的open會立即返回。但是,如果沒有進程已經爲讀而打開一個FIFO,name只寫open將會出錯返回-1.


read讀取數據時:如果沒有進程給管道里寫數據,read會阻塞,直到有數據或寫端關閉。


管道文件如果進行讀操作,讀了之後文件內存就清空,不存在了。


代碼簡單實現:

void main()
{
	int fd = open("FIFO", O_WRONLY); //A進程以只寫的方式打開,open會阻塞,直到另一個進程以另一種方式打開
	assert(fd != -1);

	printf("fifo file open over\n");
	sleep(1);
	int n = write(fd, "hello word", strlen("hello word")); //往FIFO裏面寫了hello word
	close(fd);
	printf("data write file\n");
}
void main()
{
	
	int fd = open("FIFO", O_RDONLY);//B進程以只讀打開
	assert(fd != -1);

	printf("fifo file open over\n");
	char buff[128] = {0};
	int n = read(fd, buff, 127); //從FIFO裏面讀數據,讀到buff中
	close(fd);
	printf("buff = %s\n", buff); 
	printf("data write file\n");
}

A進程會阻塞在open,等到B進程運行,以另一種方式打開FIFO時,A進程纔不阻塞,往下運行,寫入數據,B進程從FIFO管道文件中讀數據。





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