linux中的管道

管道是一种最基本的IPC机制,由pipe函数创建:

#include <unistd.h>
int pipe(int filedes[2]);

调用pipe函数就是在内核区开辟一块缓冲区(称为管道)。filedes[0]指向管道的读端,filedes[1]指向管道的写端。管道实际上就是一个打开的文件。pipe函数成功返回0,失败返回-1.

如何用管道实现两个进程间的通信?

1.父进程调用pipe函数开辟管道,得到两个文件描述符指向管道的两端。

2.父进程调用fork()创建子进程,那么子进程也有两个文件描述符指向该管道。

3.父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道写,子进程可以从管道
读,管道是环形队列实现的,数据从写端流,从读端流出,这样就实现了进程间通信。

代码实现:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<100){
			_mesg_c = "i am child!";
			write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			sleep(1);
			i++;
		}
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<100){
			memset(_mesg, ‘\0‘, sizeof(_mesg));
			read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s\n", _mesg);
			j++;
		}
	}
	return 0;
}

使用管道需要注意的4中情况:

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

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<10){
			_mesg_c = "i am child!";
			write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			sleep(1);
			i++;
		}
		close(_pipe[1]);
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<100){
			memset(_mesg, ‘\0‘, sizeof(_mesg));
			int ret = read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s : code is : %d\n", _mesg, ret);
			j++;
		}
		if (waitpid(id, NULL, 0)< 0)
		{
			return 3;
		}
	}
	return 0;
}

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

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<20){
			if (i < 10){
				_mesg_c = "i am child!";
				write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			}
			sleep(1);
			i++;
		}
		close(_pipe[1]);
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<20){
			memset(_mesg, ‘\0‘, sizeof(_mesg));
			int ret = read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s : code is : %d\n", _mesg, ret);
			j++;
		}
		if (waitpid(id, NULL, 0)< 0)
		{
			return 3;
		}
	}
	return 0;
}

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

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
	int _pipe[2];
	int ret = pipe(_pipe);
	if (ret == -1){
		printf("create pipe error! errno code is : %d\n", errno);
		return 1;
	}
	pid_t id = fork();
	if (id < 0){
		printf("fork error!");
		return 2;
	}
	else if (id == 0){ //child
		close(_pipe[0]);
		int i = 0;
		char *_mesg_c = NULL;
		while (i<20){
			if (i < 10){
				_mesg_c = "i am child!";
				write(_pipe[1], _mesg_c, strlen(_mesg_c) + 1);
			}
			sleep(1);
			i++;
		}
	}
	else{ //father
		close(_pipe[1]);
		char _mesg[100];
		int j = 0;
		while (j<3){
			memset(_mesg, ‘\0‘, sizeof(_mesg));
			int ret = read(_pipe[0], _mesg, sizeof(_mesg));
			printf("%s : code is : %d\n", _mesg, ret);
			j++;
		}
		close(_pipe[0]);
		sleep(10);
		if (waitpid(id, NULL, 0)< 0)
		{
			return 3;
		}
	}
	return 0;
}

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

时间: 2024-10-20 05:08:38

linux中的管道的相关文章

Linux中的管道与重定向

前言: 这篇博文主要参考了鸟哥的<鸟哥的Linux私房菜>和杨鹏(NetSnake)的<Linux服务器架设>这两本书,以及在网络上查阅的资料.此博文作为我阅读<鸟哥的Linux私房菜>和<Linux服务器架设>这本书的读书笔记.那么接下来就让我们依次了解它们. 概述: 熟悉操作系统的朋友,常常会听到.用到管道和重定向这两个词,那么究竟什么是管道,什么是重定向?他们对我有用吗?可以说,管道和重定向是操作系统的精髓之一,在操作系统的进程.程序和管理等各方面,都

linux中的管道和重定向

I/O重定向: Linux: >: 覆盖输出 >>:追加输出 set -C: 禁止对已经存在文件使用覆盖重定向:  强制覆盖输出,则使用 >| set +C: 关闭上述功能 2>: 重定向错误输出 2>>: 追加方式 &>: 重定向标准输出或错误输出至同一个文件 <:输入重定向 <<:Here Document 管道:前一个命令的输出,作为后一个命令的输入 命令1 | 命令2 | 命令3 | ...

Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信: 实现机制: 管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息.一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管

Linux中重定向、管道和grep命令总结

今天我们来讲下Linux中的重定向.管道和grep命令.由于重定向和管道知识点比较少,但是又比较重要所以和grep命令一起讲. 在将重定向我们先讲下系统的标准输入和输出.在Linux中标准输入(STDIN 0)对应设备:键盘:标准输出(STDOUT 1)和标准错误输出(STDERR 2)对应设备:显示器.重定向就是将标准输入输出重新定位到指定位置或者设备中(比如:文件). I/O重定向 set –C 禁止对已存在的文件进行覆盖重定向 强制覆盖>| set +C 关闭上述功能 输出重定向: >:

Linux中可用于管道操作的命令总结

在Linux中药进行稍复杂的操作,通常需要借助管道命令"|"多个命令的组合,形式如下: command 1 |  command 2 |  command 3 -- 在linux中有些命令可以直接用于管道命令中,有些则不可以,对于不可以直接用于管道的命令需要借助xargs命令: find ./ -type f | xargs md5sum >> md5_rc1.txt find ./ -type f  -print| xargs md5sum >> md5_rc

Linux中IO重定向和管道

IO重定向和管道 根据冯诺依曼原理的知识,计算机运行有数据流的输入和输出,称之为IO. Linux中一切皆文件思想,表现为具体的文件. 在linux中打开的文件都有一个fd(File Descriptor):文件描述符 程序:指令+数据 读入数据:Input 输出数据:Output Linux给程序提供三种I/O设备: 1. 标准输入(STDIN): -0 默认为接受键盘输入2. 标准输出(STDOUT):-1 默认为输出到终端窗口3. 标准错误(STDERR):-2 默认为输出到终端窗口注:标

Linux中find常见用法示例

·find   path   -option   [   -print ]   [ -exec   -ok   command ]   {} \; find命令的参数: pathname: find命令所查找的目录路径.例如用.来表示当前目录,用/来表示系统根目录.-print: find命令将匹配的文件输出到标准输出.-exec: find命令对匹配的文件执行该参数所给出的shell命令.相应命令的形式为'command' { } \;,注意{ }和\:之间的空格.-ok: 和-exec的作用

linux中用户和组的管理

一.用户的帐号管理   ①添加帐号:useradd 选项: -c, --comment 'COMMENT':在创建用户时为用户添加注释信息,一般为全名. -d, --home/PATH/TO/HOME_DIR:在创建用户的时候为用户指定家目录的绝对路径,被指定的目录应该是事先不存在的目录: -g, --gid GROUPNAME:在创建用户时,为用户指定主组: -G, --groups GROUP1[,GROUP2,...[,GROUPN]]]:在创建用户时,为用户添加附加组: -m, --cr

&lt;实训|第十一天&gt;学习一下linux中的进程,文件查找,文件压缩与IO重定向

[[email protected]~]#序言 在今后的工作中,运维工程师每天的例行事务就是使用free -m,top,uptime,df -h...每天都要检查一下服务器,看看是否出现异常.那么今天我们就讲解一下关于运维工程师例行事务的知识!  开班第十一天: [[email protected]~]#今天的课程大纲 查看进程,中断进程,切换进程 内存与swap分区 linux中文件查找的基本方法 linux中是如何解压缩文件的 关于I/O重定向的知识点 远程scp配合管道 详细讲解: [[e