• 进程间通信二(命名管道)


    在前一篇文章中,我们看到了如何使用匿名管道来在进程之间传递数据,这个方式有一个缺陷,就是这些进程必须由一个共同的祖先进程启动,这在不相关的的进程之间交换数据带来了不便。而另一种通信方式——命名管道,可以解决不相关进程间的通信问题。

    1.什么是命名管道?
    命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似。

    由于Linux中所有的事物都可被视为文件,所以对命名管道的使用也就变得与文件操作非常的统一,也使它的使用非常方便,同时我们也可以像平常的文件名一样在命令中使用。

    2.如何创建命名管道?

    #include <sys/types.h> 
    #include <sys/stat.h> 
    int mkfifo(const char *filename, mode_t mode); 

    若成功则返回0,否则返回-1,错误原因存于errno中。

    这个函数创建一个FIFO文件,注意是创建一个真实存在于文件系统中的文件,filename指定了文件名,而mode则指定了文件的读写权限。

    3.访问命名管道

    3.1 打开FIFO文件
    与打开其他文件一样,FIFO文件也可以使用open调用来打开。注意,mkfifo函数只是创建一个FIFO文件,要使用命名管道还是要先将其打开。

    但是有两点要注意,1、就是程序不能以O_RDWR模式打开FIFO文件进行读写操作,而其行为也未明确定义,因为如一个管道以读/写方式打开,进程就会读回自己的输出,同时我们通常使用FIFO只是为了单向的数据传递。2、就是传递给open调用的是FIFO的路径名,而不是正常的文件。

    打开FIFO文件通常有四种方式,

    open(const char *path, O_RDONLY);//1 
    open(const char *path, O_RDONLY | O_NONBLOCK);//2 
    open(const char *path, O_WRONLY);//3 
    open(const char *path, O_WRONLY | O_NONBLOCK);//4 
    

    在open函数的调用的第二个参数中,你看到一个陌生的选项O_NONBLOCK,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的。

    open调用的阻塞是什么一回事呢?很简单,对于以只读方式(O_RDONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_RDONLY),除非有一个进程以写方式打开同一个FIFO,否则它不会返回;如果open调用是非阻塞的的(即第二个参数为O_RDONLY | O_NONBLOCK),则即使没有其他进程以写方式打开同一个FIFO文件,open调用将成功并立即返回。

    对于以只写方式(O_WRONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_WRONLY),open调用将被阻塞,直到有一个进程以只读方式打开同一个FIFO文件为止;如果open调用是非阻塞的(即第二个参数为O_WRONLY | O_NONBLOCK),open总会立即返回,但如果没有其他进程以只读方式打开同一个FIFO文件,open调用将返回-1,并且FIFO也不会被打开。

    4. 实例

    //fifo_read.c
    include<sys/types.h> 
    #include<sys/stat.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define FIFO "/tmp/myfifo"
    main(int argc,char** argv)
    {
      char buf_r[100];
      int fd; 
      int nread;
      if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
      printf("cannot create fifoserver
    ");
      printf("Preparing for reading bytes....
    ");
      memset(buf_r,0,sizeof(buf_r));
      fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
      if(fd==-1)
      { 
        perror("open");
        exit(1);
      } 
      while(1)
      {
        memset(buf_r,0,sizeof(buf_r));
        if((nread=read(fd,buf_r,100))==-1)
        {
          if(errno==EAGAIN)
          printf("no data yet
    ");
        } 
        printf("read %s from FIFO
    ",buf_r);
        sleep(1);
      } 
      pause();
      unlink(FIFO);
    }
    

     

    //fifo_write.c
    #include<sys/types.h> 
    #include<sys/stat.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define FIFO_SERVER "/tmp/myfifo"
    main(int argc,char** argv)
    {
      int fd; 
      int nwrite;
      char w_buf[100];
      for(;;)
      { 
        memset(&w_buf, 0, sizeof(w_buf));
        fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
        printf("please input your data:
    ");
        scanf("%s", w_buf);
        if((nwrite=write(fd,w_buf,100))==-1)
        { 
          if(errno==EAGAIN)
          printf("The FIFO has not been read yet. Please try later
    ");
        } 
        else 
          printf("write %s to the FIFO
    ",w_buf);
      } 
    }

    4.1程序的编译

    [wss@localhost fifo]$ls
    fifo_read.c fifo_write.c
    [wss@localhost fifo]$gcc fifo_read.c -o read
    [wss@localhost fifo]$gcc fifo_write.c -o write
    [wss@localhost fifo]$ls
    fifo_read.c fifo_write.c read write
    [wss@localhost fifo]$

    程序的运行

    在当前console 1中运行read,在console2中运行write

    [wss@localhost fifo]$sudo ./read 
    Preparing for reading bytes....
    read from FIFO
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    read Hello from FIFO
    read FIFO from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    no data yet
    read from FIFO
    ^C[wss@localhost fifo]$

    console2

    [wss@localhost fifo]$./write 
    please input your data:
    Hello fifo!
    write Hello to the FIFO
    please input your data:
    write fifo! to the FIFO
    please input your data:
    ^C
    [wss@localhost fifo]$./write 
    please input your data:
    Hello FIFO
    write Hello to the FIFO
    please input your data:
    write FIFO to the FIFO
    please input your data:
    ^C
    [wss@localhost fifo]$
     
     
  • 相关阅读:
    Eclipse中常用的快捷键总结!不收藏后悔!
    MySQL基本命令整理,java数据库秘籍!
    centos 禁用ip v6
    win7 & win10 安装AD管理工具
    CentOS LVM 卷在线扩容
    Windows 与 Linux 、esxi下面查看内存容量和数量
    ESX/ESXi 主机上的每个插槽中安装了多少内存
    使用 esxcli storage vmfs unmap 命令在精简置备的 LUN 上回收 VMFS 删除的块
    vSphere 高级特性FT配置与管理
    vSphere HA 原理与配置
  • 原文地址:https://www.cnblogs.com/thinkinglife/p/5492806.html
Copyright © 2020-2023  润新知