欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

管道

发布时间:2025/4/5 编程问答 36 豆豆
生活随笔 收集整理的这篇文章主要介绍了 管道 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

文章目录

    • 1 无名管道
      • 1.1 用法
      • 1.2 使用示例
    • 2 有名管道
      • 2.1 mkfifo函数介绍
      • 2.2 示例

1 无名管道

1.1 用法

pipe函数:

头文件:

#include <unistd.h>

函数原型:

int pipe(int pipefd[2]);

返回值:

  • 成功:0
  • 失败:-1

特点:

  • 特殊文件(没有名字),无法使用open,但是可以使用close。
  • 只能通过子进程继承文件描述符的形式来使用
  • write和read操作可能会阻塞进程
  • 所有文件描述符被关闭之后,无名管道被销毁

使用步骤:

  • 父进程pipe无名管道
  • fork子进程
  • close无用端口
  • write/read读写端口
  • close读写端口

1.2 使用示例

#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAX_DATA_LEN 256 #define DELAY_TIME 1int main() {pid_t pid;int pipe_fd[2];char buf[MAX_DATA_LEN];const char data[] = "Pipe Test Program";int real_read, real_write;memset((void*)buf, 0, sizeof(buf));/* 创建管道 */if (pipe(pipe_fd) < 0){printf("pipe create error\n");exit(1);}/* 创建一子进程 */if ((pid = fork()) == 0){/* 子进程关闭写描述符,并通过使子进程暂停 3s 等待父进程已关闭相应的读描述符 */close(pipe_fd[1]);sleep(DELAY_TIME * 3);/* 子进程读取管道内容 */if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0){printf("%d bytes read from the pipe is '%s'\n", real_read, buf);}/* 关闭子进程读描述符 */close(pipe_fd[0]);exit(0);}else if (pid > 0){/* 父进程关闭读描述符,并通过使父进程暂停 1s 等待子进程已关闭相应的写描述符 */close(pipe_fd[0]);sleep(DELAY_TIME);if((real_write = write(pipe_fd[1], data, strlen(data))) != -1){printf("Parent write %d bytes : '%s'\n", real_write, data);}/*关闭父进程写描述符*/close(pipe_fd[1]);/*收集子进程退出信息*/waitpid(pid, NULL, 0);exit(0);} }

2 有名管道

2.1 mkfifo函数介绍

mkfifo函数:

头文件:

#include <sys/types.h> #include <sys/state.h>

函数原型:

int mkfifo(const char *filename,mode_t mode)

返回值:

  • 成功:0
  • 失败:-1

特点:

  • 有文件名,可以使用open函数打开
  • 任意进程间数据传输
  • write和read操作可能会阻塞进程
  • write具有"原子性"

使用步骤:

  • 第一个进程mkfifo有名管道
  • open有名管道,write/read数据
  • close有名管道
  • 第二个进程open有名管道,read/write数据
  • close有名管道

2.2 示例

/**fifo.c *//*** 无名管道,它只能用于具有亲缘关系的进程之间,这就大大地限制了管道的使用。有名管道的出现突破了这种限制, 它可以使互不相关的两个进程实现彼此通信。 * 该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作,使用非常方便。* 不过 FIFO 是严格地遵循先进先出规则的,对管道及 FIFO 的读总是从开始处返回数据,对它们的写则把数据添加到末尾,它们不支持如 lseek()等文件定位操作。* 有名管道的创建可以使用函数 mkfifo(),该函数类似文件中的 open()操作,可以指定管道的路径和打开的模式* * 在创建管道成功之后,就可以使用 open()、 read()和 write()这些函数了。与普通文件的开发设置一样,对于为读而打开的管道可在 open()中设置 O_RDONLY,* 对于为写而打开的管道可在 open()中设置 O_WRONLY,在这里与普通文件不同的是阻塞问题。由于普通文件的读写时不会出现阻塞问题,而在管道的读写中却有阻塞的可能,* 这里的非阻塞标志可以在 open()函数中设定为 O_NONBLOCK。下面分别对阻塞打开和非阻塞打开的读写进行讨论。* (1)对于读进程。*  若该管道是阻塞打开,且当前 FIFO 内没有数据,则对读进程而言将一直阻塞到有数据写入。*  若该管道是非阻塞打开,则不论 FIFO 内是否有数据,读进程都会立即执行读操作。即如果 FIFO内没有数据,则读函数将立刻返回 0。* (2)对于写进程。*  若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。*  若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败* * 函数原型 int mkfifo(const char *filename,mode_t mode)* 函数传入值 filename:要创建的管道名字(包含路径)* 函数传入值 mode:*  O_RDONLY:读管道*  O_WRONLY:写管道*  O_RDWR:读写管道*  O_NONBLOCK:非阻塞*  O_CREAT:如果该文件不存在,那么就创建一个新的文件,并用第三个参数为其设置权限*  O_EXCL:如果使用 O_CREAT 时文件存在,那么可返回错误消息。这一参数可测试文件是否存在* 函数返回值:*  0:成功*  EACCESS:参数 filename 所指定的目录路径无可执行的权限*  EEXIST:参数 filename 所指定的文件已存在*  ENAMETOOLONG:参数 filename 的路径名称太长*  ENOENT:参数 filename 包含的目录不存在*  ENOSPC:文件系统的剩余空间不足*  ENOTDIR:参数 filename 路径中的目录存在但却非真正的目录*  EROFS:参数 filename 指定的文件存在于只读文件系统内*/ #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h>#define MYFIFO "myfifo" /* 有名管道文件名*/#define MAX_BUFFER_SIZE PIPE_BUF /* 4096 定义在于 limits.h 中*/void fifo_read(void) {char buff[MAX_BUFFER_SIZE];int fd;int nread;printf("***************** read fifo ************************\n");/* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建*/if (access(MYFIFO, F_OK) == -1){if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST)){printf("Cannot create fifo file\n");exit(1);}}/* 以只读阻塞方式打开有名管道 */fd = open(MYFIFO, O_RDONLY);if (fd == -1){printf("Open fifo file error\n");exit(1);}memset(buff, 0, sizeof(buff));if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0){printf("Read '%s' from FIFO\n", buff);}printf("***************** close fifo ************************\n");close(fd);exit(0); }void write_fifo(void) {int fd;char buff[] = "this is a fifo test demo";int nwrite;sleep(2); //等待子进程先运行/* 以只写阻塞方式打开 FIFO 管道 */fd = open(MYFIFO, O_WRONLY | O_CREAT, 0644);if (fd == -1){printf("Open fifo file error\n");exit(1);}printf("Write '%s' to FIFO\n", buff);/*向管道中写入字符串*/nwrite = write(fd, buff, MAX_BUFFER_SIZE);if(wait(NULL)) //等待子进程退出{close(fd);exit(0);}}int main() {pid_t result;/*调用 fork()函数*/result = fork();/*通过 result 的值来判断 fork()函数的返回情况,首先进行出错处理*/if(result == -1){printf("Fork error\n");}else if (result == 0) /*返回值为 0 代表子进程*/{fifo_read();}else /*返回值大于 0 代表父进程*/{write_fifo();}return result; }

参考资料:

  • [野火]i.MX Linux开发实战指南
  • 总结

    以上是生活随笔为你收集整理的管道的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。