进程间的通信--(一)管道

来源:互联网 发布:注册域名后如何使用 编辑:程序博客网 时间:2024/05/21 17:30

进程间的通讯方式有很多种:管道通信,共享内存,消息队列,信号量、远程过程调用,以及网络部分的通过套接字(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]);       }


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

磁盘,内存存储方式

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

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