在Linux下的进程间通信之匿名管道

每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到。所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2 在从内核缓冲区把数据读走。

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

调用pippe函数时在内核中开辟一块缓冲去(称为管道)用于通信,它有一个读端,一个写端,然后通过fileds参数传出给用户程序两个文件描述符,fileds[0]指向管道的读端,fileds[1]指向管道的写端,所以管道在用户程序看起来就像一个打开的文件,通过read 或者write;向这个文件读写数据实际是在读写内核缓冲区。

管道是实现进程间的通信需要经过以下几步:

1).创建一个管道

2).创建两个进程

3).分别关闭一个进程的读端,另一个的写端

4).实现通信

程序具体如下:

(一)

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

int main()

{

int _pipe_fd[2]={-1,-1};

int _pipe=pipe(_pipe_fd);

if(_pipe<0){

perror("pipe");

exit(1);

}

int _pid=fork();

if(_pid<0){

perror("fork");

exit(2);

}else if(_pid==0){//child

close(_pipe_fd[0]);

char buf[1024]="hello world\n";

fflush(stdout);

int count =10;

while(count--){

char buf[1024]="hello world\n";

}

sleep(5);

}

else{//father

close(_pipe_fd[1]);

char buf[1024];

while(1){

memset(buf,‘\0‘,sizeof(buf));

ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));

if(_size<0){

perror("read");

exit(3);

}else{

printf("%s",buf);

}

}

}

}

return 0;

}

运行结果为:

hello world

hello world

hello world

hello world

hello world

hello world

hello world

hello world

hello world

hello world

因为读端一直循环,一直在读,而写端并没有在写,所以读端最终会阻塞。

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

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

int main()

{

int _pipe_fd[2]={-1,-1};

int _pipe=pipe(_pipe_fd);

if(_pipe<0){

perror("pipe");

exit(1);

}

int _pid=fork();

if(_pid<0){

perror("fork");

exit(2);

}else if(_pid==0){//child

close(_pipe_fd[0]);

//char buf[1024]="hello world\n";

//fflush(stdout);

int count =10;

while(count--){

char buf[1024]="hello world\n";

write(_pipe_fd[1],buf,strlen(buf));

sleep(2);

}

close(_pipe_fd[1]);

}

else{//father

close(_pipe_fd[1]);

char buf[1024];

int j=0;

while(j++ < 15){

memset(buf,‘\0‘,sizeof(buf));

ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));

if(_size<0){

perror("read");

exit(3);

}else{

printf("%s",buf);

}

}

int status=0;

if(waitpid(_pid, &status,0)==_pid){

printf("wait sucess,sigcode\n:%d",status & 0xFF);

break;

}

}

return 0;

}

程序运行结果为:

hello world

hello world

hello world

hello world

hello world

hello world

hello world

hello world

hello world

hello world

wait sucess,sigcode:0

(三)

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

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

int main()

{

int _pipe_fd[2]={-1,-1};

int _pipe=pipe(_pipe_fd);

if(_pipe<0){

perror("pipe");

exit(1);

}

int _pid=fork();

if(_pid<0){

perror("fork");

exit(2);

}else if(_pid==0){//child

close(_pipe_fd[0]);

int count =10;

while(count--){

char buf[1024]="hello world\n";

fflush(stdout);

if(count>5)

{

write(_pipe_fd[1],buf,strlen(buf));

}

sleep(2);

}

close(_pipe_fd[1]);

}

else{//father

close(_pipe_fd[1]);

char buf[1024];

int j=0;

while(j++ < 15){

memset(buf,‘\0‘,sizeof(buf));

ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));

if(_size<0){

perror("read");

exit(3);

}else{

printf("%s",buf);

}

}

int status=0;

if(waitpid(_pid, &status,0)== _pid){

printf("wait sucess,sigcode:%d\n",status & 0xFF);

}

}

return 0;

}

程序运行结果:

hello world

hello world

hello world

hello world

wait sucess,sigcode:0

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

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

int main()

{

int _pipe_fd[2]={-1,-1};

int _pipe=pipe(_pipe_fd);

if(_pipe<0){

perror("pipe");

exit(1);

}

int _pid=fork();

if(_pid<0){

perror("fork");

exit(2);

}else if(_pid==0){//child

close(_pipe_fd[0]);

int count =10;

while(count--){

char buf[1024]="hello world\n";

fflush(stdout);

if(count>5)

{

write(_pipe_fd[1],buf,strlen(buf));

}

sleep(2);

}

}

else{//father

close(_pipe_fd[1]);

char buf[1024];

int j=0;

while(j++ < 3){

memset(buf,‘\0‘,sizeof(buf));

ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));

if(_size<0){

perror("read");

exit(3);

}else{

printf("%s",buf);

}

}

close(_pipe_fd[0]);

sleep(10);

int status=0;

if(waitpid(_pid, &status,0)== _pid){

printf("wait sucess,sigcode:%d\n",status & 0xFF);

}

}

return 0;

}

程序运行结果:

hello world

hello world

hello world

wait sucess,sigcode:13

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

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

int main()

{

int _pipe_fd[2]={-1,-1};

int _pipe=pipe(_pipe_fd);

if(_pipe<0){

perror("pipe");

exit(1);

}

int _pid=fork();

if(_pid<0){

perror("fork");

exit(2);

}else if(_pid==0){//child

close(_pipe_fd[0]);

int count =10;

while(1){

char buf[1024]="hello world\n";

fflush(stdout);

write(_pipe_fd[1],buf,strlen(buf));

sleep(2);

}

}

else{//father

close(_pipe_fd[1]);

char buf[1024]

int status=0;

if(waitpid(_pid, &status,0)== _pid){

printf("wait sucess,sigcode:%d\n",status & 0xFF);

}

sleep(10);

}

return 0;

}

程序运行结果便是一直被阻塞。

由此可见管道的特点为:

1):主要用于父子进程间的通信,或者是有血缘关系的进程。

2):是单向通信的,且内部有保护机制。

3):其生命周期随进程。

时间: 2024-11-05 15:54:10

在Linux下的进程间通信之匿名管道的相关文章

Linux进程间通信 -- 使用匿名管道

在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据. 一.什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号“|"来使用管道,但是管理的真正定义是什么呢?管道是一个进程连接数据流到另一个进程的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入. 举个例子,在shell中输入命令:ls -l

进程间通信IPC—匿名管道(pipe)和命名管道(fifo)

管道内部如何实现-大小,组织方式,环形队列? 一.进程间通信有多种方式,本文主要讲解对管道的理解.管道分为匿名管道和命名管道. (1)管道( pipe ):又称匿名管道.是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. (2)命名管道 (named pipe或FIFO) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. 二.管道 1. 管道的特点: (1)管道是半双工的,数据只能向一个方向流动:双方通信时,需要

进程间通信之匿名管道

管道由pipe函数创建 #include<unistd.h> int pipe(int filedes[2]); 调用pipe函数在内核中开辟一块缓冲区(就是管道)用于通信,filedes[0]指向管道的读端,filedes[1]指向管道的写端.pipe函数调用成功返回0,调用失败返回-1. 比如,父进程关闭读端,子进程关闭写端.代码如下: 1   #include<stdio.h> 2   #include<string.h> 3   #include<unis

Python进程间通信之匿名管道

匿名管道 管道是一个单向通道,有点类似共享内存缓存.管道有两端,包括输入端和输出端.对于一个进程的而言,它只能看到管道一端,即要么是输入端要么是输出端. os.pipe()返回2个文件描述符(r, w),表示可读的和可写的.示例代码如下: #!/usr/bin/python import time import os def child(wpipe): print('hello from child', os.getpid()) while True: msg = 'how are you\n'

Linux系统编程——进程间通信:命名管道(FIFO)

命名管道的概述 无名管道,由于没有名字,只能用于亲缘关系的进程间通信(更多详情,请看<无名管道>).为了克服这个缺点,提出了命名管道(FIFO),也叫有名管道.FIFO 文件. 命名管道(FIFO)不同于无名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据. 命名管道(FIFO)和无名管道(pipe)有一

linux下的IO重定向与管道相关的知识简析

一.bash重定向部分简单翻译 1.1.bash手册关于重定向短短的注解(因为过于经典,所以摘录出来) 我的翻译要开始毁经典啦... 参考:https://blog.csdn.net/spch2008/article/details/51433353/ https://www.cnblogs.com/lqminn/archive/2013/05/30/3108283.htmlhttps://bash.cyberciti.biz/guide/Here_stringshttps://bbs.csdn

谈谈Linux下的数据流重定向和管道命令

一.标准输入.标准输出.错误输出概述 1.标准输入(stdin)是指令数据的输入,代码为0,使用<或者<<,默认是键盘. 2.标准输出(stdout)是指令执行成功返回的结果,代码为1,使用>或者>>,默认在屏幕显示. 3.标准错误输出(stderr)是指令执行失败返回的错误信息,代码为2,使用2>或者2>>,默认是屏幕. 二.数据流重定向的使用      1."<":指定输入的数据媒介来源(tr 'a-z' 'A-Z' &l

Linux下的I/O与管道

阅读目录 1. 标准输入输出 2.输入输出重定向 3.tr命令 4. 管道和tee 5.练习  1.标准输入输出 (1)linux 给程序提供三种I/O设备 标准输入 :(STDIN)    - 0   默认接受来自键盘的输入 标准输出 :(STDOUT) - 1   默认输出到终端窗口 标准错误 :(STDEER)  - 2   默认输出到终端窗口 (2)输入设备有:键盘.鼠标.扫描仪.摄像头等 输出设备有:打印机.显示器.投影仪等 2.输入输出重定向 〉正确输出 2〉错误输出 &〉全部输出(

linux下的进程通信之管道

概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需要加锁,基于字节流不需要定义数据结构 缺点:速度慢,容量有限,只能用于父子进程之间,使用场景狭窄 基本原理: 一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用.当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息.当管道被放满信息的时候,尝试放入信息的进程