进程间的通讯方式有很多种:管道通信,共享内存,消息队列,信号量、远程过程调用,以及网络部分的通过套接字(socket)来通讯,首先我们来了解一下管道通信。

一、管道

 

引入:在现实中的一些管道,比如水管、气管都起着运输作用,在进程通信中管道也起着对信息数据的承载运输作用,所谓管道通信就是开辟一块空间,进程在里面进行读写(如图一所示),这一块空间就是我们所说的管道文件,那管道文件和我们普通的文件有什么不同呢?为什么我们不能开辟一个普通文件进行读写呢?

 

基本信息:通信分为半双工通信、全双工通信。半双工通信就是指通信双方不能同时进行通信,只能一段发送一端接收,全双工通信是指通信双方即可发送消息也可接收消息。我们现在所说的管道通信就是半双工通信。之所以把管道设为半双工通信原因:A进程既可写可读,B可读的情况,当A写入一个数据时,读数据所读取的数据也可能是自己写入的数据,没有意义。

类别:管道分为有名管道和无名管道

1、有名管道:应用于任意两个进程之间的单向传递,文件目录树(在磁盘中存储)中有一个标识,仅仅占用了一个结点,没有占用磁盘上的任何内存,在使用中数据缓存在内存里,只在使用时开辟内存,读取一次后自动清空。

注:Linux文件系统中,每一个存放在磁盘上的文件由两部分组成:数据块:实际存放文件数据的磁盘块;inode:Linux内部用于描述文件特性的数据结构。inode含有关于文件的大部分信息,包括文件数据块。

不使用普通文件的原因:普通文件从磁盘进行io操作,耗费时间;管道是在内存上重新开辟一块空间,读写数据时,直接在内存上读取

2、无名管道:

定义:相对于有名管道,使用时产生,不使用时释放,不在系统上有任何痕迹,无名管道因其没有任何标识,所以只能应用于父子进程之间,子进程会拷贝父进程的文件表数组,其拷贝是浅拷贝,只是定义了一个指针,其共享一个文件描述符

使用:

1、有名管道

创建:(以命令方式)mkfifo +文件名   函数方式   谁调用命令

打开:open以只写打开管道文件时,没有文件以读/读写方式大开时,函数不返回

写入:write(fd,buff,size);

读取:read(fd,buff,size);读取数据并把数据清空??memset

关闭:close(fd);

2、无名管道

创建打开:(以函数方式)int pipe(int fd[2])形参加中括号相当于指针  

fd[0] ,读 fd[1]写,实质上是一个文件描述符指向文件

写write(fd[0],buff,size)

读read(fd[1],buff,len)

关close(fd[1]);close(fd[0]);

代码:有名管道

写端代码:

#include<stdio.h>
  #include<fcntl.h>
  #include<string.h>
  #include<unistd.h>
  #include<stdlib.h>
  #include<assert.h> 
  
    void  main()
    {
       int fd=open("FIFO",O_WRONLY);
        assert(fd!=-1);
        printf("open success\n");
        char buff[128]={0};
        while(1)
       {
           printf("please input:");
           fgets(buff,128,stdin);
           write(fd,buff,strlen(buff)-1);
           if(strncmp(buff,"end",3)==0)
           {
                exit(0);
            }
        }
       close(fd);
   }

读端:

#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<unistd.h>
void main()
{
   int fd=open("FIFO",O_RDONLY);
   assert(fd!=-1);
   printf("open success\n");
   char buff[128]={0};
   int count=0;
   while(1)
   {
      read(fd,buff,127);
      printf("read: %s\n",buff);
      count++;
      if(strncmp(buff,"end",3)==0)
      {
         printf("word number:\n",count);
           break;
      }
     }
   close(fd);
 }

无名管道:

 

#include<stdio.h> 
#include<fcntl.h> 
#include<string.h>
#include<unistd.h> 
#include<stdlib.h> 
#include<assert.h>
 void main() 
{ 
   int fd[2]={0};
   int pipe1=pipe(fd);
    pid_t pid=fork(); 
    if(pid==0) 
    { 
        close(fd[1]); 
       //printf("this is child\n"); 
        char buff[128]={0}; 
        while(1)
         { 
             read(fd[0],buff,127); 
             printf("read:%s\n",buff); 
            if(strncmp(buff,"end",3)==0) 
              { 
                 break; 
               }
          }
      }
      else
      { 
        // printf("this is parent\n") 
           close(fd[0]); 
           while(1)
           { char buff[128]={0};
            printf("please input:\n"); fgets(buff,128,stdin); 
             write(fd[1],buff,strlen(buff)-1);
              if(strncmp(buff,"end",3)==0) 
             { break; } 
             sleep(3); 
            } 
      } 
            close(fd[1]); 
            close(fd[2]); 
}

 

 


未解决问题:把管道文件的标识符放在磁盘上?为什么


 

 

磁盘,内存存储方式

 

管道的默认值是多少?能不能修改管道大小?

管道操作的内核实现(空间的大小,读写偏移量的变化 )