Linux_进程间通信_1)管道

一.进程间通信的背景及目的

     1)背景

            进程间具有独立性,直接交互并不方便,内核提供一个公共资源,多个进程通过这个公共资源进行交互

     2)目的

            数据传输,资源共享,通知事件,进程控制

二.进程间通信的几种方式

管道,消息队列,共享内存,信号量,信号

三.管道

  1.管道分类:匿名管道和命名管道

  2.管道的概念:把从一个进程连接到另一个进程的一个数据流称为一个“管道”。

  3.本质:通过文件描述符来管理管道,也是内核提供的一段内存(队列)

  4.匿名管道

        a)头文件:#include <unistd.h>

        b) 函数原型: int pipe(int fd[2])

        c) 参数:fd文件描述符数组,其中fd[0]表示读端(0像嘴巴),fd[1]表示写端(1像笔)

        d) 返回值:成功返回0,失败返回错误代码

        e)调用过程:(要边读编写)

            

     f)写一个小栗子:

          从标准输入读数据,写进管道,读取管道,写到标准输出上

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main(void){
  5     int fd[2];
  6     if(pipe(fd)==0){ //成功
  7         char buf[1024]={0};
  8         int size=sizeof(buf);
  9         int len;
 10         while(fgets(buf,size,stdin)){
 11             len=strlen(buf);
 12             if(write(fd[1],buf,len)!=len)
 13                 break;
 14             memset(buf,0x00,size);
 15             if(read(fd[0],buf,size)==-1)
 16                 break;
 17             if(write(1,buf,len)!=len)
 18                 break;
 19         }
 20     }else{
 21         perror("pipe");
 22         return -1;
 23     }
 24     return 0;
 25 }            

  g)父子进程可以同时调用一个管道

  h)管道的限制:

    1)只能在有亲缘关系的进程间使用。

    2)管道是半双工,只能由一端向另一端,需要双方通信时,需要建立两个管道。

    3)管道的生命周期随进程

    4)内核会对管道进行同步和互斥。

    5)管道提供流式服务

 i)父子进程同时使用一个管道,父进程读,子进程写

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 
  5 int main(void){
  6     int fds[2];
  7     if(pipe(fds)==-1){
  8         perror("pipe");
  9         return -1;
 10     }
 11     int pid=fork();
 12     if(pid==-1){
 13         perror("fork");
 14         return -1;
 15     }
 16     if(pid==0){ //child answer for pipe write
 17         close(fds[0]);
 18         char *buf="hello-world";
 19         write(fds[1],buf,strlen(buf));
 20         close(fds[1]);
 21     }else{ //father answer for read
 22         close(fds[1]);
 23         char buf[1024]={0};
 24         read(fds[0],buf,sizeof(buf));
 25         printf("%s\n",buf);
 26         close(fds[0]);
 27     }
 28     return 0;
 29 }                   

  5.命名管道

    a)由来:由于匿名管道必须有共同的祖先才能进行通信,如果我们想在不相关的进程之间通信,可以使用FIFO文件来完成,它被叫做命名管道。(创建的文件就是常说的管道文件)

    b)创建一个命名管道:

           1.使用命令行mkfifo filename  

           2.使用函数mkfifo

                  ·)头文件: #include <sys/types.h>

                                         #include <sys/stat.h>

                  ·)函数原型:int mkfifo(const char *pathname, mode_t mode);

                  ·)参数:pathname文文件名,mode是文件的权限

   c)使用命名管道进行进程间通信

  1 #include <stdio.h>                                                                                                   
  2 #include <stdlib.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <sys/types.h>
  6 
  7 //sever answer for read
  8 int main(void){
  9     mkfifo("letter.p",0644);
 10     int fd=open("letter.p",O_RDONLY);
 11     if(fd==-1) perror("open"),exit(1);
 12 
 13     char buf[1024]={0};
 14     while(1){
 15         memset(buf,0x00,sizeof(buf));
 16         int ret=read(fd,buf,sizeof(buf)-1);
 17         if(ret==-1){
 18             perror("read");
 19             return -1;
 20     
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <fcntl.h>
  4 #include <sys/stat.h>
  5 #include <sys/types.h>
  6 
  7 int main(void){
  8     int fd=open("letter.p",O_WRONLY);
  9     if(fd==-1) perror("open"),exit(1);
 10 
 11      char buf[1024]={0};
 12      while(1){
 13          memset(buf,0x00,sizeof(buf));
 14          printf("Client Enter#");
 15          fflush(stdout);
 16          scanf("%s",buf);
 17          write(fd,buf,strlen(buf));
 18          }
 19     close(fd);
 20     return 0;
 21 }                

      d)命名管道的实现本质

              连接内核缓存,磁盘需要挂载到某个文件时才可用。假如A和B通过管道文件进行通信,管道文件的硬链接数为3,其实是A和B通过管道找到内核缓存,并挂载到内核缓存上,删除了管道文件进程AB仍继续,只是文件名删除了,文件中没有任何东西,只是连接到内核缓存。

  6.匿名管道和命名管道的区别

     1)匿名管道由pipe函数创建并打开

     2)命名管道由mkfifo函数创建,用open打开

     3)只有创建和打开的方式不同,之后完成同样的事情。


 

·

猜你喜欢

转载自blog.csdn.net/warrior_harlan/article/details/81077645