Linux进程通信之管道(FIFO)

简介: Linux进程通信之管道(FIFO)

1. 何为管道

我的理解就是管道是一个类似于队列的缓冲区,数据先进先出。一个进程发送数据,一个进程接受数据

2. 管道分类

2.1 无名管道

无名管道适用于有亲缘关系的进程,如父子进程。因为子进程的内存空间是直接拷贝的父进程的内存空间,所以父进程创建管道后得到的文件描述符也被拷贝了一份,而其他没有亲缘关系的进程则无法的到该文件描述符(没有文件名与之对应)。

创建无名管道的接口:

#include <unistd.h>
int pipe(int pipefd[2])

例子:

#include<stdio.h>
#include<unistd.h>
/* 父进程生成数据, 子进程取出数据并打印 */
int main(void)
{
  int fd[2];
  int ret = 0;
  int data = 0;
  ret = pipe(fd);
  if (ret < 0) {
    perror("pipe error");
    return -1;
  }
  ret = fork();
  if (ret == 0) { // 子进程
    while(1) {
      ret = read(fd[0], &data, sizeof(data));
      if (ret < 0) {
        printf("read error");
        return -1;
      }
      printf("data: %d\n", data);
    }
  }
  else {    // 父进程
    while(1) {
      data += 1;
      write(fd[1], &data, sizeof(data));
      sleep(1); // 一秒钟产生一个数据
    }
  }
  close(fd[0]);
  close(fd[1]);
  return 0;
}

2.2 有名管道

有名管道在没有亲缘关系的进程之间也能够使用,顾名思义,有名管道就是给管道命一个名字,也就是创建了一个文件,该文件称为管道文件。与普通文件不同的是,管道文件的数据是先进先出的,每个数据只能取一次,取了就没了,并且不能够使用lseek函数改变偏移量。

需要注意:

  • 管道建立好后,在打开管道文件的时候,管道的两端读写必须分别打开,有任何一方未打开,则在调用open的时候就阻塞。比如,一个进程以写的方式打开管道文件,但没有任何进程以读的方式打开,那么就会阻塞在open函数,直到某个进程取以读的方式打开管道文件
  • 管道大小是有最大值的,可以使用宏PIPE_BUF(limits.h)查看。
  • 管道默认是阻塞的,在没有数据可读的时候,读操作会阻塞。

例子:

read_pipe.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#define FIFO_NAME "./fifo_test"
/* 读取管道内的数据并打印, 每两秒读取一次 */
int main(void)
{
  int ret = 0;
  int fifo_fd;
  int data = 0;
  // 打开管道
  fifo_fd = open(FIFO_NAME, O_RDONLY);
  if (fifo_fd < 0) {
    perror("open fifo error");
    return -1;
  }
  printf("[read] open ok\n");
  while(1) {
    // 读取数据
    ret = read(fifo_fd, &data, sizeof(data));
    if (ret < 0) {
      perror("read error");
      return -1;
    }
    printf("data: %d\n", data);
    sleep(2);
  }
  close(fifo_fd);
  return 0;
}

write_pipe.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#define FIFO_NAME "./fifo_test"
/* 创建管道, 向管道内写入数据,每一秒写入一次 */
int main(void)
{
  int ret = 0;
  int fifo_fd;
  //char *data = "hello World";
  int data = 0;
  // 没有就创建
  if (access(FIFO_NAME, F_OK) == -1) {
    ret = mkfifo(FIFO_NAME, 0777);
    if (ret < 0) {
      perror("mkfifo error\n");
      return -1;
    }
  }
  // 打开管道
  fifo_fd = open(FIFO_NAME, O_WRONLY);
  if (fifo_fd < 0) {
    perror("open fifo error");
    return -1;
  }
  printf("[write] open ok\n");
  while(1) {
    // 写入数据
    data += 1;
    write(fifo_fd, &data, sizeof(data));
    sleep(1);
  }
  close(fifo_fd);
  return 0;
}


目录
相关文章
|
3天前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第17天】重定向在Linux中改变命令I/O流向,默认有&quot;&gt;&quot;覆盖输出至文件及&quot;&gt;&gt;&quot;追加输出至文件末尾,便于保存结果;使用&quot;&lt;&quot;从文件读取输入而非键盘,高效处理数据。文件描述符如0(stdin)、1(stdout)、2(stderr)标识I/O资源,支持读写操作。管道以&quot;|&quot;连接命令,使前一命令输出成为后一命令输入,如排序用户或找出CPU占用最高的进程,构建复杂数据处理流程。
18 9
|
4天前
|
Linux 调度
Linux源码阅读笔记05-进程优先级与调度策略-实战分析
Linux源码阅读笔记05-进程优先级与调度策略-实战分析
|
5天前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第14天】输出重定向可将命令结果存入文件,如`&gt;`覆盖写入或`&gt;&gt;`追加写入。输入重定向从文件读取数据,如`&lt;`代替键盘输入。这些操作利用文件描述符(如0:stdin, 1:stdout, 2:stderr)管理I/O。管道`|`连接命令,使前一命令输出作为后一命令输入,便于数据处理,如排序用户`sort -t: -k3 -n /etc/passwd | head -3`或查找CPU占用高的进程`ps aux --sort=-%cpu | head -6`。
18 4
|
4天前
|
Linux API C语言
Linux源码阅读笔记02-进程原理及系统调用
Linux源码阅读笔记02-进程原理及系统调用
|
5天前
|
Linux
Linux 查找进程所在目录
Linux 查找进程所在目录
17 0
|
8天前
|
缓存 Linux Shell
【在Linux世界中追寻伟大的One Piece】Linux进程控制
【在Linux世界中追寻伟大的One Piece】Linux进程控制
15 0
|
5天前
|
NoSQL 关系型数据库 MySQL
Linux学习记录---(1、基本命令)
该博客文章提供了Linux系统中基本命令的使用记录,包括文件和目录操作、Redis服务管理、MySQL数据库操作以及Tomcat服务器的启动和检查。
Linux学习记录---(1、基本命令)
|
2天前
|
Linux
会玩这10个Linux命令,一定是个有趣的IT男!
会玩这10个Linux命令,一定是个有趣的IT男!
|
6天前
|
运维 Ubuntu Linux
Linux系统之ncdu命令的基本使用
【8月更文挑战第8天】Linux系统之ncdu命令的基本使用
14 2
Linux系统之ncdu命令的基本使用
|
2天前
|
安全 Linux 开发者
Linux笔记之ldd命令详解
`ldd`命令是Linux环境下一个非常实用的工具,用于显示一个程序运行时所需的共享库依赖。它帮助开发者和系统管理员快速诊断程序运行问题,特别是在处理"找不到库文件"或者"错误的库文件版本"等错误时。然而,出于安全的考虑,对于不信任的可执行文件,应该慎用 `ldd`命令,可以考虑使用其他工具如 `objdump`。总的来说,懂得如何妥善且安全地使用 `ldd`,对于维护一个稳定和高效的Linux系统来说,是非常重要的。
17 9