Linux-进程间通信(一、匿名管道与命名管道)

####LINUX进程间通信(二、消息队列)

####匿名管道

头文件:#include
函数原型:int pipe(int fd[2]);
返回值:成功返回0,失败返回错误代码
注:fd:文件描述符数组,fd[0]代表读端,fd[1]代表写端

####用法:
#####单个进程中的管道几乎没有任何用处,通常,调用pipe的进程接着调用fork,从而创建了一个父进程与子进程之间的半双工的IPC通道。在当前进程假如进行读操作时,就可关闭写端(fd[1])如图:
Linux-进程间通信(一、匿名管道与命名管道)_第1张图片


#####示例:假设现有一对父子进程,子进程需要读取屏幕上输入的信息,再通过管道将信息传给父进程,父进程再将该信息打印到屏幕上。
#####分析:
#####①先要清楚哪些资源是父子进程必须共有的,在fork之前就得定义,在此例子中就是匿名管道pipe;
#####②如果当前进程是父进程时:由于要做的是从管道读取数据,那么就关闭写端;读取完成后将数据打印到屏幕上;
#####③如果当前进程是子进程:关闭读端;将stdin的信息读取并写入到管道中,等待父进程读取。


#####实现如下:

#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
	//creat pipe
	int fd[2] = {0};
	if(pipe(fd) == -1){
		perror("pipe");
		exit(1);
	}

	//pipe create success
	int res = fork();
	if(res > 0){
		//father
		close(fd[1]);
		char buf[1024] = {0};
		ssize_t tmp = read(fd[0],buf,sizeof(buf)-1);
		if(tmp == -1){
				perror("read");
				exit(1);
		}else if(tmp == 0){
			printf("read done\n");
			exit(0);
		}else{
			printf("father read : %s",buf);
		}
	}else if(res == 0){
		//child
		close(fd[0]);
		char tmp[256] = {0};
		printf("child say : ");
		fflush(stdout);
		read(0,tmp,sizeof(tmp)-1);
		if(write(fd[1],tmp,strlen(tmp)) == -1){
			perror("write");
			exit(1);
		}
		//子进程正常退出
		close(fd[1]);
		exit(0);
	}else{
		perror("fork");
		exit(1);
	}
	return 0;
}

#####运行结果:
Linux-进程间通信(一、匿名管道与命名管道)_第2张图片


####管道特点:
#####1、只能用于有亲缘关系的进程之间的通信;
#####2、管道生命周期随进程;进程退出管道释放;
#####3、管道拥有同步与互斥机制;
#####4、具有半双工的特点;(要想实现双向通信,可建立两个管道)


####管道读写规则
#####1、当管道中没有数据可读时:若pipe采取的是不阻塞方法,则直接read返回-1;采取是阻塞时,进程阻塞直到等待数据可以读;
####2、当管道满时:采用不阻塞方式将调用返回-1;反之write阻塞,直到有程序读走数据。
#####注:若想修改是否阻塞选项,需使用pipe2函数。具体用法自行man一下。

int pipe2(int pipefd[2], int flags);


####命名管道(FIFO):相当于创建一个文件,通过一个进程读 一个写来完成通信


#####使用方法:FIFO创建成功后,一般的文件I/O函数(close,read,write,unlink等)都可用于FIFO。

//使用mkfifo命令创建一个名为filaname的命名管道。
mkfifo filename

//使用函数创建
函数原型:int mkfifo(const char* filename, mode_t mode);
参数:filename为所要创建的文件名,mode为文件权限.
返回值:成功返回0,失败返回-1

#####注:FIFO是一种文件类型(p)


####匿名管道与命名管道的区别:
#####1、匿名管道必须适用于有亲缘关系的进程之间;命名管道没有要求;
#####2、匿名管道通过fd[0],fd[1]进行读写;命名管道通过特殊的FIFO文件进行读写。


#####示例:client——server进程使用FIFO进行通信。
#####首先由服务器端先执行,创建FIFO文件,然后read阻塞等待有人向文件中写入数据,一旦client执行并写入数据,便开始进行“通信”。(由于是半双工,便只模拟实现了从client向server端发送数据)

server.c

#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
	if( mkfifo("myfifo",0666) == -1){
		perror("mkfifo");
		exit(1);
	}
	
	//FIFO creat success
	char buf[1024] = {0};
	int rfd = open("myfifo",O_RDONLY);
	while(1){
		printf("please wait...\n");
		if(rfd > 0){
			//open myfifo success
			printf("client say : ");
			fflush(stdout);
			ssize_t count = read(rfd,buf,sizeof(buf)-1);
			if(count > 0){
				buf[count] = 0;
				printf("%s",buf);
			}else if(count == 0){
				printf("client close\n");
				exit(0);
			}else{
				perror("read");
				exit(1);
			}
		}else{
			//open return -1,open failed
			perror("open");
			exit(1);
		}
	}
	close(rfd);
	return 0;
}

client.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
	int wfd = open("myfifo",O_WRONLY);
	if(wfd == -1){
		perror("open");
		exit(1);
	}

	//open success
	char buf[1024] = {0};
	while(1){
		printf("client send : ");
		fflush(stdout);
		ssize_t count = read(0,buf,sizeof(buf)-1);
		if(count > 0){
			buf[count] = 0;
			write(wfd,buf,strlen(buf));
		}else{
			perror("read");
			exit(1);
		}
	}
	close(wfd);
	return 0;
}

Makefile

.PHONY:all
all : server client

server:server.c
	gcc $^ -o $@
	
client:client.c
	gcc $^ -o $@

.PYHONY : clean
clean:
	rm server client myfifo

####运行结果显示:
Linux-进程间通信(一、匿名管道与命名管道)_第3张图片
#####注:1、一定要先运行server,否则没有创建myfifo文件,client将会打开失败,直接报错终止。
#####2、当同时运行多个client,一个server时,server将会全部接受client写入的信息;
#####3、当运行多个server,多个client时,此时一个client写入数据,随机只有一个server进程读取到信息。(同步互斥的体现)

你可能感兴趣的:(Linux,进程间通信,匿名管道,命名管道,FIFO)