设为首页 收藏本站
查看: 2225|回复: 0

[经验分享] linux 管道

[复制链接]

尚未签到

发表于 2018-5-20 15:13:13 | 显示全部楼层 |阅读模式
  
  管道(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;
}  运行结果:
DSC0000.jpg

  (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;
}  运行结果:
DSC0001.jpg

  (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;
}  运行结果:
DSC0002.jpg

  (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;
}  运行结果;
DSC0003.jpg

  (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;
}  运行结果:
DSC0004.jpg

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-467351-1-1.html 上篇帖子: LINUX IPTABLES 设定 下篇帖子: Linux权限及权限管理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表