Linux基础篇十二——管道

原创 2016年07月15日 20:40:42

管道是 Linux 支持的最初 Unix IPC 形式之一,我们可以使用管道使得两个进程之间进行通信。

管道通信实现的本质:控制同一文件在两个进程中仅打开读端或写端进行收发数据。

1.匿名管道

顾名思义,匿名管道是我们在进程里创建出来并且没有给其赋予指定文件名的一类管道,它可用于两个具有亲属关系的进程之间的通信。

在我们创建子进程时,子进程会创建自己的地址空间但是会复制父进程的文件描述符表,所以在子进程和父进程里我们使用同样的文件描述符指向的是同一个文件,并且,在我们打开文件时分别使用读方法和写方法打开我们找到的是同一个文件但是我们得到的描述符是不一样的。如图示



在上图里面,我们不难看出,管道文件被父子进程共享,这就说明了进程间通信的本质是共享数据。

匿名管道的特点:
·依赖于文件系统
·只能运用于有关系的进程 eg:父进程 子进程之间
**进程打开文件不进行关闭,在进程退出时文件被自动关闭
·管道的生命周期和进程相同
·管道内部提供进程间同步与互斥机制
·单向数据通信
管道的特殊状态:
·管道的写端写满之后会进行停止等待,读端类似
·管道的读端关闭,但写端没有关闭并且持续写入,此时,写端会收到异常信号并关闭
·管道的写端关闭,但读端没有关闭并且持续读取,直到管道结尾并返回0.


匿名管道的创建:

使用#include <unistd.h> int pipe(int fd[2]) 函数创建匿名管道,给出一个简单的例子

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<string.h>

int main()
{
	int pipe_fd[2];
	if(pipe(pipe_fd) < 0)
	{
		perror("pipe");
		return 1;
	}
	pid_t id = fork();
	//child
	int i = 0;
	if(id == 0)
	{
		close(pipe_fd[0]);
		const char*msg = "I am child pro...\n";
		int count = 5;
		while(1)
		{
			write(pipe_fd[1],msg,strlen(msg));
			if(count -- == 0)
				break;
			printf("child write data :%d\n",++i);
		}
		//close(pipe_fd[1]);
	}
	//father
	else
	{
		close(pipe_fd[1]);
		char buf[1024];
		int count = 5;
		while(count -- > 0)
		{
			memset(buf,'\0',sizeof(buf));
			ssize_t _s = read(pipe_fd[0],buf,sizeof(buf)-1);
			if(_s >0)
				printf("client -> server: %s\n",buf);
			else if(_s == 0)
			{
				printf("read pipe EOF...\n");
				break;
			}
			else
				break;
		}
		//close(pipe_fd[0]);
		int status = 0;
		pid_t ret = waitpid(id,&status,0);
		if(ret == id)
		{
			printf("wait success...\n");
			printf("get sig: %d",status&0xff);
			printf("exit code: %d",status >> 8&0xff);
		}
	}
	return 0;

}
**我们使用status来接收程序退出的状态码,而它的低八位是退出信号,高八位是退出码

2.命名管道

与匿名管道不同,命名管道不仅可以用于具有亲属关系的进程之间的通信,还可以用于完全无关系的两个管道的通信。我们使一个进程负责创建管道文件另一个进程只需要打开该管道文件就可以在两个进程之间进行通信.

我们仍然使用一个例子来说明命名管道的通信:

client端程序

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<fcntl.h>

int main()
{
	int fd = open("./myfifo",O_WRONLY);
	if(fd < 0)
	{
		perror("open error...");
		return 1;
	}
	char buf[1024];
	while(1)
	{
		memset(buf,'\0',sizeof(buf));
		printf("Please enter# ");
		fflush(stdout);
		ssize_t _s = read(1,buf,sizeof(buf));
		if(_s > 0)
		{
			buf[_s-1]='\0';
			write(fd,buf,strlen(buf));
		}
	}
	close(fd);
	return 0;
}

server端程序:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

int main()
{
	if(mkfifo("./myfifo",S_IFIFO | 0644) < 0)
	{
		perror("mkfifo");
		return 1;
	}

	int fd = open("./myfifo",O_RDONLY);
	if( fd < 0 )
	{
		perror("open error...");
		return 2;
	}
	char buf[1024];
	while(1)
	{
		memset(buf,'\0',sizeof(buf));
		ssize_t _s = read(fd,buf,sizeof(buf)-1);
		if(_s > 0 )
		{
			printf("Client->Server# %s\n",buf);
		}
		else
		{
			break;
		}

	}
	close(fd);
	return 0;
}

我们让客户端进行数据的写入让服务端进行数据的读出,始终保持整个通信处于半双工的状态,并且,谁创建谁回收,我们让服务端自己回收关闭我们的管道文件。这样我们就完成了两个毫无关系的进程之间的通信。

一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

管道有容量,它的容量大小存储于一个叫做PIPE_BUF的字段里,它规定了管道缓冲区的大小。其位于 include/linux/limits.h中,我们可以自行查看。不同的内核版本可能会有所不同。Posix.1 要求 PIPE_BUF 至少为 512 字节,red hat 7.2 中为 4096。

管道的原理:管道实际上是在内核创建了一个inode和一个指向它的固定大小的内核缓冲区,读写的文件描述符不同但指向了同一块内核和缓冲区。管道pipe是一类特殊的文件pipefs,在磁盘里没有映像,只存在于内存中,这样设计的原因是处于对管道文件读写速度的优化。

如果我们需要实现全双工的通信方式就在两个进程之间创建两个管道,一个正向通信另一个反之。


版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux基础篇 进程通信——管道

IPC(InterProcess Communication)进程间通信 每个进程各⾃自有不同的⽤用户地址空间,任何⼀一个进程的全局变量在另⼀一个进程中都看不到所以进 程之间要交换数...
  • zw_1510
  • zw_1510
  • 2016年07月12日 16:38
  • 551

(续)linux程序设计之c基础教程——管道

本节补充管道相关的知识,但是本节课不属于原来的(linux程序设计之c基础教程)当中的知识点! 这里另作补充: linux 管道 管道是Linux中很重要的一种通信方式,是把一个程序的输...

Linux线程间数据交换——管道篇

参考资料 [1]linux 线程(FIFO)先进先出 [2]linux管道的那点事

linux基础编程:进程通信之管道

在文章《linux基础编程:进程通信之信号》中,我们看到信号作为进程之间的通信方式。但是传送的信息之限于一个信号值。而本文将会介绍Linux支持的最初Unix IPC之一:管道和命名管道,它允许进程之...

【Linux基础】无名管道

1. 无名管道的概述 平时我们所说管道,就是指无名管道,它具有以下特点: 管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立两个管道 只能用于具有亲缘关系的进程之间通信,也就是父...

Linux学习----Shell基础(环境变量,命令别名与快捷键、历史命令、输出重定向、管道符、通配符)

Shell是一个命令解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统程序,用户可以用Shell来启动、挂起、甚至是编写一些程序。     Shell 还是一个功能相当强大的编...

Linux基础知识总结-过滤器、重定向与管道

过滤器、重定向与管道是linux里一个比较重要的概念,这样能够把linux的指令和文件组合起来,帮助我们更有效率的处理数据。 基本概念与操作: 操作系统在内核之上是需要开发很多的应用的,在linux上...

Linux基础之IO重定向及管道详解(涉及tr、tee命令)

我在刚开始接触IO重定向时,经历了由懂到不懂然后了然的过程,当然现在的我也不可能说对于IO重定向就彻底懂了,只是在解决一些问题或实现某些结果时不会因为IO重定向的问题而迷惑了。      ...

【Linux基础】重定向与管道

Shell命令在执行时,会自动打开三个标准文件,即标准输入文件(stdin),一般对应终端的键盘;标准输出文件(stdout)和标准出错输出文件(stderr),这两个文件对应终端的屏幕。但在实际应用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux基础篇十二——管道
举报原因:
原因补充:

(最多只允许输入30个字)