linux 管道 ---- 单向通信


管道(pipe):最基本的IPC机制,单向通信

管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。

1、分类:

(1)、管道(无名管道):pipe   管道是用环形队列实现的

#include <unistd.h>

int pipe(int filedes[2]);

pipe 函数:filedes参数传出给用户程序两个文件描述符(filedes[0]指向管道的读端,filedes[1]指向管道的写端)

通过read(filedes[0])或者write(filedes[1]),向这个文件读写数据其实是在读写内核缓冲区。

pipe函数调用成功返回0,调用失败返回-1。

步骤:1.创建管道;     2.fork创建子进程;

3.父子各关闭不需要的进程描述符(可利用read()、write())。

(2)、命名管道(有名管道):FIFO

创建:

#include <sys/types.h>

#include <sys/stat.h>

int mknod(const char *path,mode_t mod,dev_t dev);

int mkfifo(const char *path,mode_t mode);

调用成功都返回0,失败都返回-1

2、管道大小及工作特点:

在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:

限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节(4096字节),使得它的大小不象文件那样不加检验地增长。

使用单个固定缓冲区也会带来问题。即:管道满时,写阻塞;空时,读阻塞。

注:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。

3、管道的环形队列:

管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个片段。

管道的一端连接一个进程的输出,这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。

管道空时,读等待;管道满时,写等待;当两个进程都终结的时候,管道也自动消失。

4、管道的实现方式:

管道:单向通信

创建管道,并执行通信:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
    int _pipe_fd[2]={-1,-1};//create pipe
    if(pipe(_pipe_fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    pid_t _pid=fork();//create init
    if(_pid < 0)
    {
        perror("fork");
        exit(2);
    }
    else if(_pid == 0)//Child
    {
        close(_pipe_fd[0]);//close child read
        int count=10;//child write
        char buf[]="hello friends";
        while(count--)
        {
            write(_pipe_fd[1],buf,strlen(buf));
            sleep(1);
        }
        //close(_pipe_fd[1]);//close child write
        exit(0);//exit can return and close file by itself
    }
    else//Father
    {
        close(_pipe_fd[1]);//close father write
        char buf[1024];//father read
        
        while(1)
        {
            memset(buf,‘\0‘,sizeof(buf));
            ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf)-1);
            if(_size > 0)
            {
                buf[_size]=‘\0‘;
                printf("%s\n",buf);
            }
            else if(_size == 0)
            {
                printf("Pipe is empty,child quit\n");
                exit(3);
            }
         }
    }
    return 0;
}

运行结果:

(1).如果所有指向管道端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有

进程 从管道的读端数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像

读到文件末尾一样。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
    int _pipe_fd[2]={-1,-1};//create pipe
    if(pipe(_pipe_fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    pid_t _pid=fork();//create init
    if(_pid < 0)
    {
        perror("fork");
        exit(2);
    }
    else if(_pid == 0)//Child
    {
        close(_pipe_fd[0]);//close child read
        int count=10;//child write
        char buf[]="hello friends";
	while(count--)
        {
            write(_pipe_fd[1],buf,strlen(buf));
            sleep(1);
        }
        //close(_pipe_fd[1]);//close child write
        exit(0);//exit can return and close file by itself
    }
    else//Father
    {
        close(_pipe_fd[1]);//close father write
        char buf[1024];//father read
        
        while(1)
        {
            memset(buf,‘\0‘,sizeof(buf));
            ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf)-1);
            if(_size > 0)
            {
                buf[_size]=‘\0‘;
                printf("%s\n",buf);
            }
            else if(_size == 0)
            {
                printf("Pipe is empty,child quit\n");
                exit(3);
            }
         }
    }
    return 0;
}

运行结果:

(2).如果有指向管道端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写

端的 进程也没有向管道中写数据,这时有进程从管道读端数据,那么管道中剩余的数

据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
    int _pipe_fd[2]={-1,-1};//create pipe
    if(pipe(_pipe_fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    pid_t _pid=fork();//create init
    if(_pid < 0)
    {
        perror("fork");
        exit(2);
    }
    else if(_pid == 0)//Child
    {
        close(_pipe_fd[0]);//close child read
        int count=10;//child write
        char buf[]="hello friends";
	while(count)
	{
		if(count > 5)//write not close all
		{
			write(_pipe_fd[1],buf,strlen(buf));
		}
		sleep(1);
		count--;
	}
        //close(_pipe_fd[1]);//close child write
        exit(0);//exit can return and close file by itself
    }
    else//Father
    {
        close(_pipe_fd[1]);//close father write
        char buf[1024];//father read
        
        while(1)
        {
            memset(buf,‘\0‘,sizeof(buf));
            ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf)-1);
            if(_size > 0)
            {
                buf[_size]=‘\0‘;
                printf("%s\n",buf);
            }
            else if(_size == 0)
            {
                printf("Pipe is empty,child quit\n");
                exit(3);
            }
         }
    }
    return 0;
}

运行结果:

(3).如果所有指向管道端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进

程向管道的端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
    int _pipe_fd[2]={-1,-1};//create pipe
    if(pipe(_pipe_fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    pid_t _pid=fork();//create init
    if(_pid < 0)
    {
        perror("fork");
        exit(2);
    }
    else if(_pid == 0)//Child
    {
        close(_pipe_fd[0]);//close child read
        int count=10;//child write
        char buf[]="hello friends";
	while(count--)
        {
            write(_pipe_fd[1],buf,strlen(buf));
            sleep(1);
        }
        //close(_pipe_fd[1]);//close child write
        exit(0);//exit can return and close file by itself
    }
    else//Father
    {
        close(_pipe_fd[1]);//close father write
        char buf[1024];//father read
        
        while(1)
        {
           if(count==0)
	   {
		close(_pipe_fd[0]);//close father read
		break;
	    }
            memset(buf,‘\0‘,sizeof(buf));
            ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf)-1);
            if(_size > 0)
            {
                buf[_size]=‘\0‘;
                printf("%s\n",buf);
            }
            else if(_size == 0)
            {
                printf("Pipe is empty,child quit\n");
                exit(3);
            }
         }
         int status=0;
  	 if(waitpid(_pid,&status,0) == _pid)
  	 {
  		printf("code; %s sig: %s\n",(status >> 8)& 0xFF,status & 0xFF);
  	 }
    }
    return 0;
}

运行结果;

(4).如果有指向管道端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读

端的 进程也没有从管道中读数据,这时有进程向管道写端数据,那么在管道被写满时

再 次write会阻塞,直到管道中有空位置了才写入数据并返回。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
    int _pipe_fd[2]={-1,-1};//create pipe
    if(pipe(_pipe_fd) < 0)
    {
        perror("pipe");
        exit(1);
    }
    pid_t _pid=fork();//create init
    if(_pid < 0)
    {
        perror("fork");
        exit(2);
    }
    else if(_pid == 0)//Child
    {
        close(_pipe_fd[0]);//close child read
        int count=10;//child write
        char buf[]="hello friends";
	while(count--)
        {
            write(_pipe_fd[1],buf,strlen(buf));
            sleep(1);
        }
        //close(_pipe_fd[1]);//close child write
        exit(0);//exit can return and close file by itself
    }
    else//Father
    {
        close(_pipe_fd[1]);//close father write
        char buf[1024];//father read
        
        while(1)
        {
            memset(buf,‘\0‘,sizeof(buf));
            ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf)-1);
            if(_size > 0)
            {
                buf[_size]=‘\0‘;
                printf("%s\n",buf);
            }
            else if(_size == 0)
            {
                printf("Pipe is empty,child quit\n");
                exit(3);
            }
         }
         int status=0;
  	 if(waitpid(_pid,&status,0) == _pid)
  	 {
  		printf("code; %s sig: %s\n",(status >> 8)& 0xFF,status & 0xFF);
  	 }
    }
    return 0;
}

运行结果:

时间: 2024-10-29 19:08:09

linux 管道 ---- 单向通信的相关文章

Linux管道及IO重定向小练习

1.统计/usr/bin目录下的文件个数 [[email protected] ~]# ls /usr/bin | wc -l 1306 [[email protected] ~]# 2.取出当前系统上所有用户的SHELL,要求,每种SHELL只显示一次,并且按顺序进行显示 [[email protected] ~]# cut -d: -f7 /etc/passwd | sort -u /bin/bash /bin/nologin /bin/sync /bin/tcsh /sbin/halt /

linux 管道--转

linux 管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别. 有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建. Linux管道的实现机制 在Linux中,管道是一种使用非常频繁的通信机制.从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为: ·      限制管道

Linux入门-7 Linux管道、重定向以及文本处理

Linux管道.重定向以及文本处理 1 Linux多命令协作:管道及重定向 管道和重定向 2 Linux命令行文本处理工具 文件浏览 基于关键字搜索-grep 基于列处理文本-cut 文本统计-wc 文本排序-sort 删除重复行 文本比较-diff 检查拼写-aspell 处理文本内容-tr 搜索替换-sed 开源的一个重要理念:不要重复发明轮子. 很多开源软件都是现有软件.代码.功能的重新组合. <大教堂与集市> 1 Linux多命令协作:管道及重定向 管道和重定向 Linux中,大多数命

linux管道详解

原文链接:http://blog.csdn.net/qq_38646470/article/details/79564392 符号表示 | 和管道特别形象. 作用: 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别. 有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建. 实现机制 在Linux中,管道是一种使用非常频繁的通信机制.从

Linux管道及重定向

Linux管道及重定向 对shell有一定了解的人都知道,管道和重定向是 Linux 中非常实用的 IPC 机制.在shell中,我们通常使用符合'|'来表示管道,符号'>'和'<'表示重定向.那么管道和重定向的真实含义(定义)又是什么呢? 管道 管道的定义 管道就是一个进程与另一个进程之间通信的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入.它是半双工运作的,想要同时双向传输需要使用两个管道.管道又可以分为匿名管道和命名管道,而shell中使用到的是匿名管道,所以本文仅描述

linux管道的容量和内部组织方式

1.管道容量  count=65536,即64KB #include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<fcntl.h> #include<errno.h> #include<stdlib.h> #include<string.h> int main() { int _pipe[2]; if(pipe(_pipe)==-1) { print

linux 管道

linux的管道:前一个命令的输出当做后一个命令的输入 管道的形式:命令1 |命令2|命令3|.... eg:echo"redhat"|passwd --stdin hive cat /etc/passwd|sort cut -d: -f1 /etc/passwd|sort

Linux管道(具名FIFO)

概述 (匿名)管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信. 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道;命名管道是一种特殊类型的文件. 管道应用 1)创建一个命名管道 命名管道可以从命令行上创建: $ mkfifo <filename> 命名管道在程序里创建: #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *

linux管道学习(一)

最近学习了管道 pipe,在这里进行一下总结. 这里贴一段自己的实做代码 struct node{ int a; long b; }; int main() { int field[2]; pid_t pid; char buf[256]; int returned_count; pipe(field); //fcntl(field[0], F_SETFL, O_NONBLOCK); int status; pid = fork(); if(pid < 0) { printf("Error