进程间通信( 匿名管道与有名管道的创建)

进程间通信( 匿名管道与有名管道的创建)
*
刚接触linux在学习过程中对所学的知识点总是忘记 ,也不知道具体该怎么去使用,希望通过写博文的方法将自己所学的知识点展现出来,记录自己学习的过程让自己不断进步。*

匿名管道
没有名字的管道(仅用于具有亲缘关系如父子、兄弟第)的进程通信。

匿名管道的创建:pipe(int pipefd[2])

#include<unistd.h>  //所包含调用函数使用的头文件
int pipe(intpipefd[2];
pipefd:用于接收匿名函数调用创建成功后的返回值
*在这里我们需要注意的是在匿名管道创建的过程中分为读与写两部分
pipefd[0]代表读数据 pipefd[1]代表写入数据
返回值 创建成功:0  失败:-1

 - List item

匿名管道的原理:在这里就以父子进程为例好了,fork()相信大家的了解到了这个函数的功能 创建一个子进程,子进程复制了父进程的描述符表,因此子进程也继承了父亲中所具有的特征,并且他们指向同一个管道,这是因为父子进程是指向的同一个通道,所有就可以进行相互间的通信。

因为管道是半双工单向通信因此在使用过程中我们首先要搞清楚数据流的走向,在读和写操作父子进程中只能打开一种操作同时关闭另外一种操作,拿父子进程的匿名管道代码来演示吧。

//匿名管道实现从父进程写入子进程读出 大家也可以把读写的位置调换一下看运行的效果
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>

int main()
{
    int pipefd[2];
    if(pipe(pipefd)<0){
         perror("pipe error");
         return -1;
     }
    
    pid_t pid;
    pid=fork();
    if(pid<0){
          perror("fork error");
          return -1;
     }
     else if(pid==0){
          close(pipefd[1]);//子进程创建成功关闭写操作进行读
          char buff[1024]={0};//在这里最好先初始化
          read(pipefd[0],buff,1024);
          printf("read data:%s\n",buff);
          close(pipefd[0]);//读入完毕输出后关闭读窗口
      }
      else{
                     
           close(pipefd[0]);//关闭读操作父进程进行写操作
           write(pipefd[1],"i love you",10};
           sleep(1);
           close(pipefd[1]);
       }
        
           return 0;
   }                                                              
 

执行结果展示:
在这里插入图片描述

下面在说一下匿名管道的特性(借鉴的一位博主总结)
1.只能用于具有亲缘关系的进程间通信;
2.管道是半双工单向通信,不用的文件描述符用一个另外一个不用,不用的文件描述符就要close关闭;
3.管道的生命周期随进程(打开管道的所有进程退出,管道释放);
4.管道是面向字节流传输数据;
5.内核会对管道操作进行同步与互斥;
临界资源:大家都能访问到的共享资源
临界区:对临界资源进行操作的代码
同步:临界资源访问的可控时序性(一个操作完另外一个才可以操作)
互斥:对临界资源同一时间的访问性

命名管道
命名管道:文件系统可见,是一个特殊类型文件,命名管道可以应用于同一个主机上任意进程间通信这也是相对于匿名管道的一个很大优势。

命名管道的创建:

 #include <sys/types.h>
 #include <sys/stat.h>
 int mkfifo(const char *pathname, mode_t mode);
 *pathname :创建的文件名路径  mode_t :管理文件的权限
 成功返回:0   失败返回:-1

命名管道打开特性:
1.如果用只读打开命名管道,open()函数将阻塞等待直至有其他进程以写的方式打开这个命名的管道,如果没有进程以写的方式打开这个命名的管道,那么这个程序就会一直停在那里。
2.如果用只写打开命名管道,open()函数将阻塞等待直至有其他进程以读的方式打开这个命名的管道,如果没有进程以读的方式打开这个命名管道,程序也会停在此处。
3.如果用读写打开命名管道,则不会阻塞但这样的话管道就成了单向的。

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>

int main()
{
         //用mkfifo创建管道
         umask(0);//将掩码设置为0
         if(mkfifo("./file",0644)<0){
              if(errno==EEXIST);
              else{
                   perror("mkfifo error");
                   return -1;
                   }
             }
          //打开管道
          int fd=open("./file",o_WRONLY);//这里只以写的方式打开
          if(fd<0){
                   
                   perror("open  error");//打开失败
                   return -1;
              }
                
                   printf("open success and start write:\n");
          while(1)
          {
                   char buff[1024]={0};
                   scanf("%s",&buff);//注意在输入的时候一定不要忘了加去地址符
                   write(fd,buff,strlen(buff));
                   sleep(1);
          }  
                   close(fd);
                   return 0;
}        

只以读的形式打开文件

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>

int main()
{
         //用mkfifo创建管道
         umask(0);//将掩码设置为0
         if(mkfifo("./file",0644)<0){
              if(errno==EEXIST);
              else{
                   perror("mkfifo error");
                   return -1;
                   }
             }
          //打开管道
          int fd=open("./file",o_RDONLY);//这里只以读的方式打开
          if(fd<0){
                   
                   perror("open  error");//打开失败
                   return -1;
              }
                
                   printf("open success and start read:\n");
          while(1)
          {
                   char buff[1024]={0};
                   int n_read=read(fd,buff,sizeof(buff));
                   if(n_read>0){
                         printf("read context:%s\n",buff);
                         }
                   if(n_read==0){
                         printf("read finished\n");//读取完毕
                         sleep(2);
                         }      
          }  
                       close(fd);
                       return 0;
}        

运行结果:
左边输入右边输出
在这里插入图片描述
最后在来看一下匿名管道和命名管道的区别和联系
1、区别
匿名管道用int pipe(pipefd[2]);创建并打开匿名管道返回描述符
在这里插入图片描述命名管道用mkfifo或者int mkfifo(const char *pathname,mod_t mode);创建,创建并没有直接打开如果需要打开进行后续操作则还需要用open函数在次打开文件
在这里插入图片描述
2.联系
匿名管道和命名管道都是内核的一块缓冲区,并且都是单向通信,另外当命名管道打开open后,所有特性与匿名管道的特性几乎一样(二者的读写规则、临界资源访问的时序性、同步与互斥等)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小殷学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值