signed

QiShunwang

“诚信为本、客户至上”

管道-pipe()函数使用

2020/12/27 17:27:13   来源:

进程间通信

linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
在这里插入图片描述

进程间通信的方式

在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有:

  1. 管道(使用最简单)
  2. 信号(开销最小)
  3. 共享映射区(无血缘关系)
  4. 本地套接字(最稳定)

管道-pipe

概念:
管道是一种最基本的IPC机制,也称匿名管道,应用于有血缘关系的进程之间,完成数据传递。调用pipe函数即可创建一个管道。
在这里插入图片描述

管道具有一下特质

  1. 管道的本质是一块内核缓冲区
  2. 由两个文件描述符引用,一个表示读端,一个表示写端
  3. 规定数据从写端流入管道,从读端流出
  4. 当两个进程都终结的时候,管道也自动消失
  5. 管道的读端和写端都默认是阻塞的

管道的原理

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

管道的局限性

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

pipe()函数

函数原型

int pipe(int fd[2]);

函数参数

若函数调用成功,则fd[0]存放管道的读端,fd[1]存放管道的写端。
返回值
若成功,则返回0
若失败,则返回-1,并设置errno

函数调用成功返回读端和写端的文件描述符,其中fd[0]是读端, fd[1]是写端,向管道读写数据是通过使用这两个文件描述符进行的,读写管道的实质是操作内核缓冲区。

//父子进程之间的通信
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
	//创建管道
	//int pipe(int pipefd[2]);
	int fd[2];
	int ret = pipe(fd);
	printf("fd[0]==[%d]\n",fd[0]);
	printf("fd[1]==[%d]\n",fd[1]);
	if(ret<0)
	{
		perror("pipe error");
		return -1;
	}

	//创建子进程
	pid_t pid = fork();
	if(pid<0) 
	{
		perror("fork error");
		return -1;
	}
	else if(pid>0)
	{
		//关闭读端
		close(fd[0]);
		sleep(5);
		write(fd[1], "hello world", strlen("hello world"));	
		wait(NULL);
	}
	else 
	{
		//关闭写端
		close(fd[1]);
		
		char buf[64];
		memset(buf, 0x00, sizeof(buf));
		int n = read(fd[0], buf, sizeof(buf));
		printf("read over, n==[%d], buf==[%s]\n", n, buf);
	}
	return 0;
}

在这里插入图片描述