zoukankan      html  css  js  c++  java
  • 四十八、进程间通信——标准库中的管道操作及命名管道和匿名管道

    48.1 标准库中的管道操作

    48.1.1 标准库中的管道操作

    1 #include <stdio.h>
    2 FILE *popen(const char *cmdstring, congst char *type);
    3 int pclose(FILE *fp)
    • 函数说明:
      • 使用 popen() 创建的管道必须使用 pclose() 关闭。其实,popen/pclose 和标准文件输入/输出流中的 fopen()/fclose 十分相似。
      • 封装管道的常用操作
    • 返回值:
      • popen:成功,返回文件指针;出错,返回 NULL
      • pclose:cmdstring 的终止状态,出错返回 -1

      

      

    48.1.2 例子

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 
     5 
     6 int main(void)
     7 {
     8     FILE *fp;
     9     /** 命令执行的结果放置在 fp 指向的结构体缓存中 */
    10     fp = popen("cat /etc/passwd", "r");
    11     char buf[512];
    12     memset(buf, 0, sizeof(buf));
    13     while(fgets(buf, sizeof(buf), fp) != NULL){
    14         printf("%s", buf);
    15     }
    16 
    17     pclose(fp);
    18 
    19     printf("-----------------------------------------------------------------
    ");
    20     /** 为 wc 命令提供统计的数据 */
    21     fp = popen("wc -l", "w");
    22     /** 向 fp 指向的结构体缓存中写入数据 */
    23     fprintf(fp, "1
    2
    3
    ");
    24     pclose(fp);
    25 
    26     return 0;
    27 }

      编译运行:

      

    48.2 命名管道和匿名管道

    48.2.1 命名管道的创建

    1 #include <sys/types.h>
    2 #include <sys/stat.h>
    3 int mkfifo(const char *pathname, mode_t mode);
    • 只要对 FIFO 有适当访问权限,FIFO 可用在任何两个没有任何关系的进程间通信。
    • 本质是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在
    • 在文件系统中只有一个索引块存放文件的路径,没有数据块,所有数据块存放在内核中
    • 命名管道必须读和写同时打开,否则单独读或者单独写会引发阻塞
    • 命令 mkfifo 创建命名管道(命令内部调用 mkfifo 函数)
    • 对 FIFO 的操作与普通文件一样
    • 一旦已经用 mkfifo 创建了一个 FIFO,就可用 open 打开它,一般的文件 I/O (close、read、write、unlink 等)都可用于 FIFO
    • FIFO 相关出错信息
      • EACCES:无存取权限
      • EEXIST:指定文件不存在
      • ENAMETOOLONG:路径不存在
      • ENOENT:包含的目录不存在
      • ENOSPC:文件系统剩余空间不足
      • ENOTDIR:文件路径无效
      • EROFS:指定的文件存在于只读文件系统中

    48.2.2 命名管道例子

      创建两个没有关系的程序,即两个进程,通过命名管道进行读写

        fifo_read.c

      

     1 #include <unistd.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <fcntl.h>
     5 #include <memory.h>
     6 
     7 /** 从命名管道中读取数据 */
     8 int main(int argc, char *argv[])
     9 {
    10     if(argc < 2){
    11         printf("usage: %s fifo
    ", argv[0]);
    12         exit(1);
    13     }
    14     printf("open fifo read ...
    ");
    15     /** 打开命名管道 */
    16     int fd = open(argv[1], O_RDONLY);
    17     if(fd < 0){
    18         perror("open error");
    19     }
    20     else {
    21         printf("open file success: %d
    ", fd);
    22     }
    23 
    24     /** 从命名管道中读取数据 */
    25     char buf[512];
    26     memset(buf, 0, sizeof(buf));
    27     while(read(fd, buf, sizeof(buf)) < 0){
    28         perror("read error");
    29     }
    30     printf("%s
    ", buf);
    31 
    32     close(fd);
    33     return 0;
    34 }

      fifo_write.c

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <memory.h>
     5 #include <fcntl.h>
     6 
     7 
     8 int main(int argc, char *argv[])
     9 {
    10     if(argc < 2){
    11         printf("usage: %s fifo 
    ", argv[0]);
    12         exit(1);
    13     }
    14     printf("open fifo write...
    ");
    15 
    16     /** 打开命名管道 */
    17     int fd = open(argv[1], O_WRONLY);
    18     if(fd < 0){
    19         perror("open error");
    20         exit(1);
    21     }
    22     else {
    23         printf("open fifo success: %d
    ", fd);
    24     }
    25 
    26     char *s = "hello world";
    27     size_t size = strlen(s);
    28     if(write(fd, s, size) != size){
    29         perror("write error");
    30     }
    31     close(fd);
    32 
    33     return 0;
    34 }

      单独编译这两个文件为可执行程序,先在一个终端中运行read,再在另一个终端运行 write。

      在没有打开 write 之前,read 会阻塞,在打开之后,read 即可正常读取

    48.3 匿名管道和命名管道读写的差异

    • 相同点
      • 默认都是阻塞性读写
      • 都适用于 socket 的网络通信
      • 阻塞不完整管道(有一端关闭)
        • 单独读时,在所有数据被读取后,read 返回 0,以表示到达了文件尾部
        • 单纯写时,则产生信号 SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则 write 返回 -1,同时 errno 设置为 EPIPE
      • 阻塞完成管道(两端都开启)
        • 单纯读时,要么阻塞,要么读取到数据
        • 单纯写时,写到管道满时会出错
      • 非阻塞不完整管道(有一端关闭)
        • 单纯读时直接报错
        • 单纯写时,则产生信号 SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则 write 返回 -1,同时 errno 设置为 EPIPE
      • 非阻塞完整管道(两端都开启)
        • 单纯读时直接报错
        • 单纯写时,写到管道满时会出错
    • 不同点:
      • 打开方式不一样
      • pipe(匿名管道) 通过 fcntl 系统调用来设置 O_NONBLOCK 来设置非阻塞性读写
      • FIFO 通过 fcntl 系统调用或者 open 函数来设置非阻塞性读写
  • 相关阅读:
    软件项目管理实践之日计划
    VB.NET版机房收费系统—数据库设计
    图的邻接矩阵存储结构
    Java多态特性:重载和覆写的比較
    《实体解析与信息质量》
    cocos2d-x lua 中使用protobuf并对http进行处理
    Memcached 笔记与总结(2)编译 php-memcache 扩展
    大数据的时代意义
    大数据的时代意义
    SPSS输出结果统计表与统计图的专业性编辑及三线表定制格式
  • 原文地址:https://www.cnblogs.com/kele-dad/p/10293483.html
Copyright © 2011-2022 走看看