Linux进程间通信之管道

管道用于进程间的通信,进程间通信的 公共资源叫做临界资源,访问临界资源的代码叫做临界区 。

管道文件以p开头,管道是一种最基本的IPC机制
管道又有匿名管道和命名管道之分

匿名管道:
调用pipe函数时在内核开辟一块要缓冲区(称为管道)用于通信,但是由pipe创建的管道只能用于具有亲缘关系之间的通信,因为必须要拥有一样的文件描述符表。

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

#include<stdio.h>
#include <unistd.h>
int main()
{
    int pipefd[2]={0};
    int ret=pipe(pipefd);
     if(ret==0)
     {
     printf("pipefd[0]: %d\n",pipefd[0]);
     printf("pipefd[1]: %d\n",pipefd[1]);
    }
     return 0;
}

这里写图片描述

使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):

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

//1 pipe
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
   int pipefd[2]={0};
   int ret=pipe(pipefd);
    if(ret==-1)
    {
       perror("pipe");     
    }
    pid_t id=fork();
    if(id==0)
    {  
         int i=0;
       const char*msg="hello bit!i am child";
       close(pipefd[0]);
         while(i<10)
         {
             write(pipefd[1],msg,strlen(msg));
             sleep(1);
              i++;
       }
         close(pipefd[1]);
    }
    else
    {
         char buf[1024]={0};
         close(pipefd[1]);
         int j=0;
    while(j<100)
    {

      ssize_t s=read(pipefd[0],buf,sizeof(buf)-1);

       if(s>0)
       {
            buf[s]=0;
       printf("father: %s\n",buf);
       j++;
       }
       else
       {
           printf("end!\n");
           break;
       }
    }
    } 
    wait(NULL);
    return 0;
}

这里写图片描述

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

#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    int pipefd[2]={0};
    int ret=pipe(pipefd);
     if(ret==-1)
     {
        perror("pipe");     
     }
     pid_t id=fork();
     if(id==0)
     {  
          int i=0;
        const char*msg="hello bit!i am child";
        close(pipefd[0]);
          while(i<20)
          {
               if(i<10)
               {
          write(pipefd[1],msg,strlen(msg));//10次之后虽然写段没有关闭但是子进程已经不往管道中写数据了
               }
              sleep(1);
               i++;
        }
          close(pipefd[1]);
     }
     else
     {
          char buf[1024];
          close(pipefd[1]);
          int j=0;
     while(j<20)
     {

       ssize_t s=read(pipefd[0],buf,sizeof(buf)-1);

        if(s>0)
        {
             buf[s]=0;
        printf("father: %s\n",buf);
        j++;
        }

  }


          pid_t ret=wait(NULL);
     }
     return 0;
}

这里写图片描述

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

#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    int pipefd[2]={0};
    int ret=pipe(pipefd);
     if(ret==-1)
     {
        perror("pipe");     
     }
     pid_t id=fork();
     if(id==0)
     {  
          int i=0;
        const char*msg="hello bit!i am child";
        close(pipefd[0]);
          while(i<10)
          {

          write(pipefd[1],msg,strlen(msg));
              sleep(1);
               i++;
        }
     }
     else
     {
          char buf[1024];
          close(pipefd[1]);
          int j=0;
     while(j<3)
     {

       ssize_t s=read(pipefd[0],buf,sizeof(buf)-1);

        if(s>0)
        {
             buf[s]=0;
        printf("father: %s\n",buf);
        j++;
        }

  }
        close(pipefd[0]);
          sleep(10);
         int status=0;
          pid_t ret=waitpid(id,&status,0);
          if(ret>0)
          {
             if (WIFEXITED(status))
               {
               printf("exitCode: %d\n,sig is %d\n",(status>>8)&0xff,status&0xff);
          }

           else//如果进程不是正常退出 的
          {
               printf("child process quit not normal!\n");
                 WTERMSIG(status);
               printf("exitCode: %d\nsig is %d\n",(status>>8)&0xff,status&0xff);
}
}
          }return 0;
}

这里写图片描述

4、如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读 端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时 再次write会阻塞,直到管道中有空位置了才写入数据并返回。
管道被写满,管道是有最大容量的。
见此文: http://blog.csdn.net/persistence_s/article/details/72779358

命名管道
匿名管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信,在命名管道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一 个路径名与之关联,以FIFO的⽂文件形式存储于⽂文件系统中。命名管道是⼀一个设备⽂文件,因 此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO 相互通信。值得注意的是,FIFO(first input first output)总是按照先进先出的原则⼯工作,第一 个被写入的数据将首先从管道中读出。

这里写图片描述

写端
#include<stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h> 
#include <unistd.h> 
#include <string.h>
#include <fcntl.h>
int main() 
{   

   umask(0);
   int ret =mkfifo("./tmp",0666|S_IFIFO);    
    if(ret == -1)
{                 
   printf("mkfifo error\n");         

     return 1;                      
  }              

   int fd = open("./tmp", O_WRONLY);              
 if(fd < 0)
{         
      printf("open error\n");           

  }        
       char buf[1024]={0};
    while(1){          
          scanf("%s", buf);                           
  ssize_t ret = write(fd, buf, strlen(buf));                       
      if(ret > 0){                                                           

      if( strncmp(buf, "quit", 4) == 0 )
{                              
    break;                                   
   }                     
   } 
}
    close(fd);      return 0;   
}

读端:
#include<stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h> 
#include <unistd.h> 
#include <string.h>
#include <fcntl.h> 
int main()
{
    int fd=open("./tmp",O_RDONLY);
    if(fd<0)
    {
        perror("open");
        return -2;
    }
    char buf[1024]={0};
    while(1)
    {
        ssize_t ret=read(fd,buf,sizeof(buf)-1);
        if(ret>0)
        {

        if(strncmp(buf,"quit",4)==0)
        {
            break;
        }
        buf[ret]=0;
        printf("%s\n",buf);
        }
    }
    close (fd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值