歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

linux中的管道

管道是一種最基本的IPC機制,由pipe函數創建:
#include <unistd.h>
int pipe(int filedes[2]);
調用pipe函數就是在內核區開辟一塊緩沖區(稱為管道)。filedes[0]指向管道的讀端,filedes[1]指向管道的寫端。管道實際上就是一個打開的文件。pipe函數成功返回0,失敗返回-1.
如何用管道實現兩個進程間的通信?
1.父進程調用pipe函數開辟管道,得到兩個文件描述符指向管道的兩端。



2.父進程調用fork()創建子進程,那麼子進程也有兩個文件描述符指向該管道。



3.父進程關閉管道讀端,子進程關閉管道寫端。父進程可以往管道寫,子進程可以從管道
讀,管道是環形隊列實現的,數據從寫端流,從讀端流出,這樣就實現了進程間通信。



代碼實現:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<100){
			_mesg_c = "i am child!";
			write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			sleep(1);
			i++;
		}
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<100){
			memset(_mesg, '\0', sizeof(_mesg));
			read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s\n", _mesg);
			j++;
		}
	}
	return 0;
}
使用管道需要注意的4中情況:
1. 如果所有指向管道寫端的文件描述符都關閉了(管道寫端的引用計數等於0),仍然有
進程從管道的讀端讀數據,那麼管道中剩余的數據都被讀取後,再次read會返回0,就像
讀到件末尾樣。
測試代碼:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<10){
			_mesg_c = "i am child!";
			write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			sleep(1);
			i++;
		}
		close(_pipe[1]);
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<100){
			memset(_mesg, '\0', sizeof(_mesg));
			int ret = read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s : code is : %d\n", _mesg, ret);
			j++;
		}
		if (waitpid(id, NULL, 0)< 0)
		{
			return 3;
		}
	}
	return 0;
}
2. 如果有指向管道寫端的文件描述符沒關閉(管道寫端的引用計數大於0),持有管道寫
端的進程也沒有向管道中寫數據,這時有進程從管道讀端讀數據,那麼管道中剩余的數
據都被讀取後,再次read會阻塞,直到管道中有數據可讀了才讀取數據並返回。
測試代碼:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<20){
			if (i < 10){
				_mesg_c = "i am child!";
				write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			}
			sleep(1);
			i++;
		}
		close(_pipe[1]);
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<20){
			memset(_mesg, '\0', sizeof(_mesg));
			int ret = read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s : code is : %d\n", _mesg, ret);
			j++;
		}
		if (waitpid(id, NULL, 0)< 0)
		{
			return 3;
		}
	}
	return 0;
}
3. 如果所有指向管道讀端的文件描述符都關閉了(管道讀端的引用計數等於0),這時有進
程向管道的寫端write,那麼該進程會收到信號SIGPIPE,通常會導致進程異常終。
測試代碼:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<20){
			if (i < 10){
				_mesg_c = "i am child!";
				write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			}
			sleep(1);
			i++;
		}
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<3){
			memset(_mesg, '\0', sizeof(_mesg));
			int ret = read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s : code is : %d\n", _mesg, ret);
			j++;
		}
		close(_pipe[0]);
		sleep(10);
		if (waitpid(id, NULL, 0)< 0)
		{
			return 3;
		}
	}
	return 0;
}
4. 如果有指向管道讀端的文件描述符沒關閉(管道讀端的引用計數大於0),持有管道讀
端的進程也沒有從管道中讀數據,這時有進程向管道寫端寫數據,那麼在管道被寫滿時
再次write會阻塞,直到管道中有空位置了才寫入數據並返回。
Copyright © Linux教程網 All Rights Reserved