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私房菜 基础学习篇(第三版)

第零章 计算器概论 1 计算机:辅助人脑的好工具 接收用户指令与数据,经由中央处理器的数学与逻辑单元运算处理后,以产生或存储成有用的信息。 1.1 计算器的五大单元 输入单元,CPU控制单元,CPU算...
  • niuzhihuan
  • niuzhihuan
  • 2015年08月03日 20:17
  • 1023

《鸟哥的linux私房菜:基础学习篇》第3版 - 核心笔记(全)

一、什么是 Linux 呢?! • Unix 与 Linux 的历史     o Multics 系统:由 Bell(贝尔实验室)、MIT(麻省理工学院)与 GE(美国通     用电器)合作开发的...
  • sinat_36184075
  • sinat_36184075
  • 2017年05月19日 23:50
  • 622

TCP/IP 教程(针对LINUX的网络基础请参看 《鸟哥的Linux私房菜 服务器架设篇(第三版) 》)

TCP/IP 是针对因特网的通信协议。 在此教程中,你将了解到什么是 TCP/IP,以及它如何工作。开始学习 TCP/IP ! TCP/IP 是因特网的通信协议。 通信协议是对计算机必须遵...
  • u010794281
  • u010794281
  • 2015年09月16日 18:31
  • 1625

鸟哥的Linux基础篇整理---1

1、在 Linux 这个系统当中,几乎所有的硬件装置文件都在/dev 这个目录下。 2、几个重要的存储文件       1)、 /etc/passwad :所有的系统上的账号与...
  • zy00000000001
  • zy00000000001
  • 2017年06月25日 22:11
  • 179

基础篇:ubuntu的使用

自知转乎  教授豪   原文链接:HTTPS://zhuanlan.zhihu.com/p/32579020 一文件目录操作 在Ubuntu的的的的下面使用命令行来对文件...
  • jiachen0212
  • jiachen0212
  • 2018年01月08日 14:00
  • 891

电子书-鸟哥的Linux私房菜--基础学习篇(第3版).pdf

http://pan.baidu.com/s/1pJmGh5L 提取密码:6u6u
  • mythling
  • mythling
  • 2014年07月27日 21:14
  • 401

【鸟哥的linux私房菜】终于再次读完《Linux 基础篇》——一些感想

今年暑假才开始入门linux,听说鸟哥的书挺适合入门的,于是就开始从《鸟哥的linux私房菜——基础篇》开始学,暑假的时候,比较粗略地看过了一遍,对linux系统有了整体的概念,也做了一些小笔记,不过...
  • jiange_zh
  • jiange_zh
  • 2015年11月16日 00:28
  • 5760

Java 之JNI基础篇(一)

JNI,即Java Native Interface。它其实就是一套java与本地代码交互的接口或者说是一个协议。通俗的比喻,就是中国人讲中国话,日本人讲日本话,于是中国人碰到日本人,各说各话,无法交...
  • yingshukun
  • yingshukun
  • 2018年01月13日 18:51
  • 10033

鸟哥的Linux私房菜基础篇第三版 -- 目录

服务器端使用的OS,Linux是最最常用的,所以,日常的部署、排查问题,就不可避免的与Linux打交道,日积月累,对Linux就有了多多少少的了解。 反过来,再系统的从头开始,读一本关于Linux基础...
  • puma_dong
  • puma_dong
  • 2015年09月27日 22:49
  • 2046

JAVA语言程序设计(基础篇)第十版

Queue类 import java.util.Arrays; public class Queue { private int[] element; private int size=8; Queu...
  • summerdream_
  • summerdream_
  • 2017年07月04日 09:06
  • 715
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux基础篇十二——管道
举报原因:
原因补充:

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