进程间通信---管道

管道分为无名管道(只能在具有公共祖先的两个进程中使用----父子进程)和有名管道(可用于不同进程)

管道特点:

  1. 半双工,数据在同一时刻只能在同一方向流动
  2. 数据只能从一端写入一端读出(先入先出)
  3. 管道不是普通的文件,不属于某个文件系统,其只存在于内存中。

无名管道

通过pipe函数创建无名管道

参数: 

pipefd : 为 int 型数组的首地址,其存放了管道的文件描述符 pipefd[0]、pipefd[1]。

当创建一个管道它会创建两个文件描述符fd[0]和fd[1]   

  • fd[0]用于读管道
  • fd[1]用于写管道

一般的IO函数都可以用来操作管道(lseek()除外----因为管道先进先出特点 )

成功   返回0

失败   返回-1

 单个进程管道

 

#include<stdio.h>    
#include<unistd.h>    
int main()    
{    
    int fd[2];    
    int ret=-1;    
    char buf[1024];    
    ret=pipe(fd);    
    if(ret==-1)    
    {    
        perror("pipe");    
        return 1;    
    }    
    //写管道fd[1]    
    write(fd[1],"asdfgh",6);    
    
    //读管道    
    read(fd[0],buf,6);    
    
     printf("buf:%s\n",buf);    
        
    return 0;    
}

 父子进程管道

进程要先调用pipe,再调用fork,从而创建父进程到子进程的ipc通道         

 如果要父进程写子进程读  关闭父进程读fd[0]  关闭子进程写fd[1]

 

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{         
    pid_t pid=-1;
    int ret=-1;  
    int fd[2]; 
    char buf[1024];
    //先创建管道   
   ret=pipe(fd);
   if(ret==-1)  
   {          
       perror("pipe");
       return 1;          
   }                
   //创建父子进程
  pid=fork();        
  if(pid==0)     
  {             
      //子进程  读 关闭写
      close(fd[1]);          
      read(fd[0],buf,sizeof(buf));
      printf("buf:%s\n",buf);         
      exit(0);                   
  }                                                                                 
  else{
      //parent
      close(fd[0]);
      write(fd[1],"123456678",9);
  }     
 return 0;
}
        

 当管道的一端被关闭后  有以下规则

读管道

  • 管道有数据,read返回读到的字节数
  • 无数据
    • 当写管道没有关闭时,,read阻塞,(这里可以设置为非阻塞,没有数据直接返回-1)
    • 关闭时,read返回0(相当于读到末尾)

写管道

读管道没有关闭

  • 管道满了,write阻塞
  • 未满,返回实际写入字节数

读管道关闭

  • 进程会终止(回产生SIGPIPE,如果忽略该信号或者捕捉该信号并从其处理程序返回,则write返回-1,error设置为EPIPE)

设置为非阻塞

//先获取原来的flags

int flags=fcntl(fd[0],F_GETFL)

//这只新的flags

flsgs |= O_NONBLOCK

//设置非阻塞

fcntl(fd[0],F_SETFL,flags)

#include<stdio.h>    
#include<unistd.h>    
#include<stdlib.h>    
#include<fcntl.h>    
#include<string.h>    
int main()    
{    
    pid_t pid=-1;    
    int ret=-1;    
    int fd[2];    
    char buf[1024];    
    //先创建管道    
   ret=pipe(fd);    
   if(ret==-1)    
   {    
       perror("pipe");    
       return 1;    
   }    
   //创建父子进程    
  pid=fork();    
  if(pid==0)    
  {    
      //子进程  读 关闭写    
      close(fd[1]);    
      memset(buf,0,1024);    
      printf("子进程读取内容......\n");                                             
    int flags=fcntl(fd[0],F_GETFL);    
    flags|=O_NONBLOCK;    
    fcntl(fd[0],F_SETFL,flags);    
    ret= read(fd[0],buf,sizeof(buf));    
    if(ret==-1)  
    {
        perror("read");                                                             
        return 1;
    }
      printf("buf:%s\n",buf);
      close(fd[0]);
      exit(1);
  }
  else{
      //parent
      
      close(fd[0]);
      sleep(3);
      write(fd[1],"123456678",9);
  }
    return 0;
}

查看缓冲区的命令

可以使用ulimit -a命令查看当前系统中创建管道文件所对应的内核缓冲区大小

 查看缓冲区的函数

#include<unistd.h>

long fpathconf(int  fd,int  name)

功能:

通过name查看不同属性值

name:

  • _PC_PIPE_BUF,查看管道缓冲区大小
  • _PC_NAME_MAX,文件名字字节数的上限

成功根据name返回不同 

失败返回-1

#include<unistd.h>    
#include<stdio.h>    
int main()    
{    
    int fd[2];    
    int ret=-1;    
   ret=pipe(fd);    
   if(ret==-1)    
   {    
       perror("pipe");    
       return 1;    
   }    
   long num=fpathconf(fd[0],_PC_PIPE_BUF);    
   printf("num=%ld\n",num);    
   num=fpathconf(fd[1],_PC_NAME_MAX);    
   printf("num=%ld\n",num);                                                         
    
    
}

 有名管道

命名管道提供一个路径名与之关联,以FIFO的文件系统存在于文件系统中,两个进程彼此通过FIFO相互通信.

通过命令创建管道

 两个进程  一个写管道一个读管道

 

命名管道(FIFO)和无名管道(pipe)有一些特点是相同的,不一样的地方在于:

1) FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存中。

2) 当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。

3) FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值