Linux进程间通信(IPC)

要想进程间通信,数据交换,必须通过内核;

一个进程将数据写到内核,然后另一个进程从内核读走数据。

IPC:进程间通信(interprocess communication)

通信方式:

  • 管道
  • 信号
  • 共享映射区(无血缘关系)
  • 本地套接字

 管道:

概念:

管道是一种最基本的IPC机制,也称匿名管道,应用于有血缘关系的进程之间,完成数据传递。

特质:

  • 管道的本质是一块内核缓冲区
  • 两个文件描述符引用,一个表示读端,一个表示写段
  • 规定数据从管道的写端流入管道,从读端流出
  • 当两个进程都终结的时候,管道也自动消失
  • 管道的读端和写端默认都是阻塞的(写端写满写不进阻塞,读端读不到数据阻塞)

原理: 

  • 管道的实质是内核缓冲区,内部使用环形队列实现
  • 默认缓冲区大小是4K,可以使用ulimit -a命令获取大小
  • 实际操作时缓冲区会根据数据压力做适当调整 

局限性:

  • 数据一旦被读走,便不在管道中存在,不可反复读取
  • 数据只能在一个方向上流动,若要实现双向流动,必须使用两个管道
  • 只能在有血缘关系的进程间使用管道 

 创建管道-pipe函数:

  • 作用:创建一个管道
  • 函数原型: int pipe(int pipefd[2]);也可以写int pipe(int *pipefd)写成pipefd[2]是为了说明传两个fd。
  • 参数:若调用成功,f[0]放读端,f[1]放写端
  • 返回值:成功返回0 ;失败返回-1,并设置error值

步骤:

  1. 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]和fd[1]
  2. 父进程调用fork函数创建子进程,那么子进程也有两个文件描述符指向同一个管道
  3. 父进程关闭管道读端,子进程关闭通道写端。父进程写,子进程读 

Linux进程间通信(IPC)_第1张图片

结果:

父子进程完成管道命令: 

如:ps -aux | grep bash

文件描述符表:

Linux进程间通信(IPC)_第2张图片

 标准输出是写到终端,标准输入是从终端读

思路:我们可以使用:dup2(fd[1],STDOUT_FILENO)函数,写到管道的写端

                                    dup2(fd[0],STDIN_FILENO)函数,从管道的读端读

Linux进程间通信(IPC)_第3张图片

结果:
Linux进程间通信(IPC)_第4张图片 

 兄弟进程完成管道命令:

#include
#include
#include
#include
#include
#include 
int main()
{
	int i=0;
	int fd[2];
	int ret=pipe(fd);
	if(ret<0)
	{
		perror("pipe error");
		return -1;
	}
	for(;i<2;i++)
	{
		pid_t pid=fork();
		if(pid<0)
		{
			perror("fork error");
			return -1;
		}
		else if(pid>0)
		{
			printf("father:pid=[%d]\n",getpid());
			sleep(1);
		}
		else if(pid==0)
		{
			printf("child:pid=[%d],fpid=[%d]\n",getpid(),getppid());
			break;
		}
	}
	if(i==2)
	{
		close(fd[0]);
		close(fd[1]);
		int wstatus;
		while(1)
		{
			pid_t wpid=waitpid(-1,&wstatus,WNOHANG);
			if(wpid==0)
			{
				continue;
			}
			else if(wpid>0)
			{
				if( WIFEXITED(wstatus))
				{
					printf("child[%d],return=[%d]\n",wpid,WEXITSTATUS(wstatus));
				}
			}
			else if(wpid==-1)
			{
				printf("no child is living\n");
				break;
			}
		}
	}
	else if(i==0)
	{
		close(fd[0]);
		dup2(fd[1],STDOUT_FILENO);
		//	close(fd[1]);
		execlp("ps","ps","-aux",NULL);
		perror("execlp error");
		exit(1);
	}
	else if(i==1)
	{
		close(fd[1]);
		dup2(fd[0],STDIN_FILENO);
		//	close(fd[0]);
		execlp("grep","grep","bash",NULL);
		perror("execlp error");
		exit(1);
	}
}

注意点:要关闭父进程的管道读写端口,不然会一直阻塞。

结果:

Linux进程间通信(IPC)_第5张图片

你可能感兴趣的:(linux,服务器,运维)