Interprocess Communication - Pipes (Anonymous and Named)

Physically , pipes can be divided into communication between processes on the same host and communication between processes on different hosts . In terms of communication methods , pipes are divided into anonymous pipes and named pipes . The characteristics of anonymous pipes and named pipes are described below.

Anonymous pipe (pipe)

[Meaning] : A pipeline is a channel for the data flow of one process to another process, that is, the output of the data of one process is used as the input of the data of another process, and the pipeline acts as a bridge .

For example: when we input: ls -l | cat test where ls and cat are two processes, | stands for pipe, which means to execute the ls -l process and use the output result as the input of the cat test process, the cat process will input the The result is printed on the screen.

[Essence] : The essence of anonymous pipe communication is that the parent process frok child process, the parent and child process each have a file descriptor table, but the content of the two is the same, since the content is the same, then it points to the same pipe , that is, the parent and child processes see the same public resource.

[Creation of pipes]: Pipes are the most basic IPC mechanism, created by the pipe function:

int pipe(fd[2]); 

fd : array of file descriptors

fd[2]: Indicates the input and output ends of the pipeline. The output data flows through the pipeline to the input end. After the function is executed, the array will be assigned a value.

fd[0]: Represents the file descriptor of the pipe input.

fd[1]: Represents the file descriptor of the output end of the pipe.

[Schematic diagram of inter-process communication] : We let the parent process close the read end of the pipe, and the child process closes the write end of the pipe. The parent process can write to the pipe, and the child process can read from the pipe. The pipe is implemented with a circular queue, and data flows from the write end to the read end, thus realizing inter-process communication.


#include<stdio.h>
#include<unistd.h>
#include<string.h>

intmain()
{
	int fd [2];
	int ret = pipe(fd);
	if (ret == -1)
	{
		printf("create pipe error!\n");
		return 1;
	}
	pid_t id = fork();
	if(id < 0)
	{
		printf("frok child error!\n");
		return 2;
	}
	else if(id == 0)
	{
		//child
		close(fd[1]); //close write
		char msg[1024];
		int i = 0;
		while(i < 1024)
		{
			memset(msg,'\0',sizeof(msg));
			read(fd[0],msg,sizeof(msg));
			printf("%s\n",msg);
			++i;
		}
	}
	else
	{
		//father
		close(fd[0]); //close read
		int j = 0;
		char* str = NULL;
		while(j < 1024)
		{
			str = "i am child";
			write(fd[1],str,strlen(str)+1);
			sleep(1);
			j++;
		}
	}
	return 0;
}

使用管道是有一些限制的,两个进程通过一个管道只能实现单向通信。比如上述例子,父进程写,子进程读,如果需要子进程写,父进程读,就必须另开一个管道。

[管道的五大特性]

(1)匿名管道只能单向通信。

(2)管道只能进行在有血缘关系的进程间通信,通常用于父子进程。

(3)管道通信依赖于文件系统,即管道的生命周期随进程。

(4)管道的通信被称为面向字节流,与通信格式没有关系。

(5)管道自带同步机制,保证读写顺序一致。

[思考题]:如果只开一个管道,但是父进程不关闭读端,子进程不关闭写端,双方都保留读写端,为什么不能实现双向通信?

解析:管道的读写端是通过打开的文件描述符来传递的,因此要通信的两个进程必须从他们的公共祖先那里继承管道的文件描述符。

[匿名管道的四种特殊情况]:假设都是阻塞I/O操作,没有设置O_NONBLOCK标志。

(1)如果所有指定管道写端的文件描述符都关闭了(管道写端的引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据被读取后,再次read会返回0,就像读到文件末尾一样。

(2)如果有指向管道写端的文件描述符没有关闭(管道写端的引用计数大于0),而持有写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

(3)如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

(4)如果有指向管道读端的文件描述符没有关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读取数据,这时有进程向管道的写端写入数据,那么管道被写满时,再次 write 会阻塞,直到管道中有空位置了才写入数据并返回。

命名管道(FIFO)

[本质]:命名管道在某种程度上可以看做是匿名管道,但它打破了匿名管道只能在有血缘关系的进程间的通信。命名管道之所以可以实现进程间通信在于通过同一个路径名而看到同一份资源,这份资源以FIFO的文件形式存于文件系统中。

值得注意的是,FIFO总是按照先入先出的原则工作,第一个被写入的数据将首先从管道读出。

[管道的创建]:我们可以使用下列函数之一来创建命名管道。

int mkfifo(const char* filename,mode_t mode);
int mknod(const char* filename,mode_t mode,dev_t dev);

这两个函数都可以创建一个FIFO文件,注意是创建一个真实存在于文件系统的文件。

[filename]:指定了文件名。

[mode]:指定了文件的读写权限。

mknod是比较老的函数,而mkfifo函数更加简单和规范,所以建议在可能情况下,尽量使用mkfifo。

[作用]:在文件系统中创建一个文件,该文件用于提供FIFO功能,即命名管道。对文件系统来说,匿名管道是不可见的,它的作用仅限于在父进程与子进程之间的通信。而命名管道是一个可见的文件,因此,它可以用于任何两个进程之间的通信。





Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324499653&siteId=291194637