详解:命名管道的打开规则

前言

        在前面的文章中我们已经对命名管道进行了简单介绍,我们知道命名管道的本质就是文件系统中的一个特殊设备文件,即管道文件(FIFO)。虽然它和其他普通文件的用途不同,但它的打开方式却和普通文件相同,都是通过调用open函数来打开。通常而言,打开管道文件的方式有以下几种:

(1)只读且阻塞方式
        open(const char *pathname, O_RDONLY);
(2)只读且非阻塞方式
        open(const char *pathname, O_RDONLY | O_NONBLOCK);
(3)只写且阻塞方式
        open(const char *pathname, O_WRONLY);
(4)只写且非阻塞方式
        open(const char *pathname, O_WRONLY | O_NONBLOCK);
注:
        在这里我们需要注意一点,就是不能以 O_RDWR 方式打开管道文件,这种行为是未定义的。倘若有一个进程以读写方式打开了某个管道,那么该进程写入的数据又会被该进程本身读取,而管道一般只用于进程间的单向数据通信。

        对于上述的4种打开方式,我们将在接下来的部分进行详细介绍,并分析每一种方式所产生的的结果。

一、只读方式

1. 阻塞模式(默认)

【示例】
        在命令行模式下使用 mkfifo fifo 创建一个命名管道fifo,验证以只读且阻塞方式打开该命名管道情况下的结果。
【代码】

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
         
int main() {    
    int fd = open("fifo", O_RDONLY); //以只读且阻塞方式打开命名管道    
    if(fd == -1) {    
        printf("Failed to open pipeline.\n");    
        return -1;    
    }    
    else {    
        printf("Successfully opened the pipeline.\n");    
    }    
         
    char buf[20] = {0};    
    read(fd, buf, 20);    
    printf("read buf: %s\n", buf);                                                                                                                    
         
    close(fd);    
         
    return 0;    
}

【执行结果】
在这里插入图片描述
【分析】
        从执行结果来看,在只读且阻塞方式下打开命名管道,open 函数会进入阻塞等待状态,直到有相关进程为写而打开该管道。(另一进程代码可参考下面只写且阻塞方式情况下的示例)

2. 非阻塞模式

【示例】
        在命令行模式下使用 mkfifo fifo 创建一个命名管道fifo,验证以只读且非阻塞方式打开该命名管道情况下的结果。
【代码】

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
         
int main() {    
    int fd = open("fifo", O_RDONLY | O_NONBLOCK); //以只读且非阻塞方式打开命名管道    
    if(fd == -1) {                                                                                                                                    
        printf("Failed to open pipeline.\n");    
        return -1;    
    }    
    else {    
        printf("Successfully opened the pipeline.\n");    
        perror("result");    
    }    
         
    char buf[20] = {0};    
    read(fd, buf, 20);    
         
    close(fd);    
         
    return 0;    
}

【执行结果】
在这里插入图片描述
【分析】
        从执行结果来看,在只读且非阻塞方式下打开命名管道,open 函数会立即成功返回,即管道成功打开。

3. 总结

模式结果
阻塞模式(O_NONBLOCK disable)open 阻塞直到有相关进程为写而打开该管道
非阻塞模式(O_NONBLOCK enable)open 成功返回

二、只写方式

1. 阻塞模式(默认)

【示例】
        在命令行模式下使用 mkfifo fifo 创建一个命名管道fifo,验证以只写且阻塞方式打开该命名管道情况下的结果。
【代码】

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
#include <string.h>    
         
int main() {    
    int fd = open("fifo", O_WRONLY); //以只写且阻塞方式打开命名管道    
    if(fd == -1) {    
        printf("Failed to open pipeline.\n");    
        return -1;    
    }    
    else {    
        printf("Successfully opened the pipeline.\n");    
    }    
         
    char buf[] = "Hello FIFO";    
    write(fd, buf, strlen(buf));    
    printf("write buf: %s\n", buf);                                                                                                                   
         
    close(fd);    
         
    return 0;    
}

【执行结果】
在这里插入图片描述

【分析】
        从执行结果来看,在只写且阻塞方式下打开命名管道,open 函数会进入阻塞等待状态,直到有相关进程为读而打开该管道。(另一进程代码可参考上面只读且阻塞方式情况下的示例)

2. 非阻塞模式

【示例】
        在命令行模式下使用 mkfifo fifo 创建一个命名管道fifo,验证以只写且非阻塞方式打开该命名管道情况下的结果。
【代码】

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
#include <errno.h>    
#include <string.h>    
         
int main() {    
    extern int errno;    
         
    int fd = open("fifo", O_WRONLY | O_NONBLOCK); //以只写且非阻塞方式打开命名管道                                                                    
    if(fd == -1) {    
        printf("Failed to open pipeline.\n");    
        printf("errno: %d\n", errno);    
        perror("result");    
        return -1;    
    }    
    else {    
        printf("Successfully opened the pipeline.\n");    
    }    
         
    char buf[] = "Hello FIFO";    
    write(fd, buf, strlen(buf));    
         
    close(fd);    
         
    return 0;    
}

【执行结果】
在这里插入图片描述
【分析】
        从执行结果来看,在只写且非阻塞方式下打开命名管道,open 函数会立即出错返回,即管道打开失败,并且 errno 被置为 ENXIO,错误信息为 No such device or address

3. 总结

模式结果
阻塞模式(O_NONBLOCK disable)open 阻塞直到有相关进程为读而打开该管道
非阻塞模式(O_NONBLOCK enable)open 失败返回,并置 errno 为 ENXIO
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
匿名管道命名管道都是用于进程间通信的方式,但它们之间有一些区别。 匿名管道: 匿名管道是一种单向通信方式,只能用于父子进程或者兄弟进程之间的通信。在创建匿名管道时,操作系统会自动为其分配一个文件描述符,通过该文件描述符,进程可以进行读写操作。 匿名管道的创建方式如下: ```C int pfd[2]; pipe(pfd); // 创建匿名管道 ``` 其中,pfd[0]是管道的读端,pfd[1]是管道的写端。 匿名管道的使用方式如下: ```C char buf[1024]; pid_t pid; int pfd[2]; pipe(pfd); pid = fork(); if (pid == 0) { // 子进程 close(pfd[1]); // 关闭写端 read(pfd[0], buf, sizeof(buf)); // 读取数据 printf("child process read from pipe: %s\n", buf); close(pfd[0]); // 关闭读端 } else if (pid > 0) { // 父进程 close(pfd[0]); // 关闭读端 write(pfd[1], "hello world", strlen("hello world")); // 写入数据 close(pfd[1]); // 关闭写端 } else { perror("fork"); exit(1); } ``` 命名管道命名管道也是一种单向通信方式,但可以用于任意进程之间的通信。在创建命名管道时,需要指定一个路径名,并且需要手动创建该文件。操作系统会为其分配一个文件描述符,通过该文件描述符,进程可以进行读写操作。 命名管道的创建方式如下: ```C int fd; mkfifo("/tmp/myfifo", 0666); // 创建命名管道 fd = open("/tmp/myfifo", O_RDONLY); // 打开命名管道 ``` 其中,"/tmp/myfifo"是文件路径名,0666是文件权限。 命名管道的使用方式如下: ```C char buf[1024]; int fd; fd = open("/tmp/myfifo", O_RDONLY); read(fd, buf, sizeof(buf)); // 读取数据 printf("read from fifo: %s\n", buf); close(fd); ``` 需要注意的是,命名管道的写入操作可以在任意进程中进行,只要有权限打开该文件即可。如果多个进程同时写入数据到同一个命名管道,可能会导致数据混乱。因此,使用命名管道时需要特别注意数据的同步问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值