Linux进阶-ipc管道

news2025/2/22 20:32:23

目录

ipc管道

无名管道pipe

头文件和函数原型

pipe.c文件

Makefile文件

执行过程

有名管道fifo

函数原型

fifo.c文件

Makefile文件

执行过程

FIFO的应用场景:Linux的日志系统


ipc管道

ipc信号,一个信号从进程中产生,发送给另一个进程,传递的是信号值,没有具体的数据传递,因此可使用管道。

管道当数据从一个进程流向另一个进程时之间的连接通常是把一个进程的输出通过管道连接到另一个进程的输入Shell命令中用“|”表示

管道本质上是一个可读写的文件,借助VFS(虚拟文件系统)给应用程序提供操作接口。

管道分类:有名管道、无名管道。

例如ps -aux | grep root,|其实就是管道,将ps命令输出的数据通过管道流向grep。其实是打开了两个进程,ps命令本应是在终端显示输出,但是它通过管道将输出的信息作为grep命令的输入信息,然后通过搜索后将合适的信息显示出来。

无名管道pipe

shell操作中的“|”就是常见的无名管道。

无名管道的特点是只能在父子进程中使用,父进程在产生子进程前必须打开一个管道文件然后fork产生子进程,这样子进程通过拷贝父进程的进程地址空间获得同一个管道文件描述符以达到使用同一个管道通信的目的。此时除了父子进程外,无人知道这个管道文件描述符,所以通过这个管道的信息无法传递给其他进程。这保证了传输数据的安全性,当然也降低了管道的通用性,于是系统还提供有名管道。

拥有以下特征:

没有名字的文件(仅支持在父进程创建然后将管道文件描述符继承给子进程),因此不能使用open函数打开,但可以使用close函数关闭

半双工通信机制。

有两个文件描述符,一个只能用来读,一个只能用来写(对写操作不做任何保护)。

只能用于具有血缘关系的进程间通信,通常用于父子进程间通信

管道是基于字节流来通信的。

依赖于文件系统,它的生命周期随进程的结束而结束

写入操作不具有原子性,因此只能用于一对一的简单通信情形

管道为特殊文件,可使用read、write函数进行读写,但并不属于其他任何文件系统,并且只存在于内核的内存空间中,因此不能使用lseek()来定位

头文件和函数原型
#include <unistd.h>
int pipe(int pipefd[2]);
/*
pipefd数组用于返回两个引用管道末端的文件描述符。
pipefd[0]指管道的读取端,pipefd[1]指管道的写入端
返回值:
    0:创建成功
    -1:创建失败,并且设置errno
*/

向管道的写入端写入数据将会由内核缓冲,即写入内存中,直到从管道的读取端读取数据为止,而且数据遵循先进先出原则。

无名管道创建成功后,创建该无名管道的进程(父进程)同时掌握着管道的读取端和写入端,但是想要父子进程间有数据交互,则需要以下操作:

父进程调用pipe()函数创建无名管道,得到两个文件描述符pipefd[0]和pipefd[1],分别指向管道的读取端和写入端。

父进程调用fork()函数启动一个子进程,子进程继承父进程的两个文件描述符pipefd[0]和pipefd[1],分别指向管道的读取端和写入端。

由于无名管道是利用环形队列实现的,数据将从写入端流入管道,从读取端流出管道,达到进程间通信的目的。但是这个无名管道此时有两个读取端和两个写入端。

想要从父进程将数据传递给子进程,则父进程需要关闭读取端,子进程关闭写入端。

想要从子进程将数据传递给父进程,则父进程需要关闭写入端,子进程关闭读取端。

当不需要管道时,就在进程中将未关闭的一端关机即可。

pipe.c文件
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define MAX_DATA_LEN 256

int main(void)
{
        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){
                // 子进程
                close(pipe_fd[1]);
                sleep(3);

                if((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0){
                        printf("read size:%d\n", real_read);
                        printf("read data:%s\n", buf);
                }

                close(pipe_fd[0]);
                exit(0);
        }else if(pid > 0){
                // 父进程
                close(pipe_fd[0]);
                sleep(1);

                if((real_write = write(pipe_fd[1], data, strlen(data))) != -1){
                        printf("write size:%d\n", real_write);
                        printf("write data:%s\n", data);
                }
                
                close(pipe_fd[1]);
                waitpid(pid, NULL, 0);
                exit(0);
        }
}

Makefile文件

照旧

执行过程

有名管道fifo

有名管道可以在多个无关的进程中交换数据。有名管道不同于无名管道在于它提供了一个路径名与之关联,以一个文件形式存在于文件系统中,因此可使用open、read、write、close等函数。

虽然有名管道文件存储在文件系统中,但数据却是存在于内存中

拥有以下特征:

有名字的文件,存储在普通文件系统中

任何具有相关权限的进程都可以使用open函数来获取有名管道的文件描述符。

可使用read、write进行文件读写。

不能使用lseek()函数来定位,因为数据存储在内存中

写入操作具有原子性,支持多个用户同时写入数据而不会互相干扰

遵循先进先出原则,最先被写入FIFO的数据会最先被读处理。

函数原型
int mkfifo(const char *pathname, mode_t mode);
// mkfifo()会根据参数pathname建立特殊的FIFO文件,而参数mode为该文件的模式与权限

mkfifo()创建的FIFO文件,其他进程都可以进行读写操作,可以使用如open、read、write、close等。

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所指定的文件存在于只读文件系统中。

使用FIFO的过程中,当一个进程对管道进行读操作时:

若该管道是阻塞类型,且当前FIFO内没有数据,则对读进程而言将一直阻塞到有数据写入。

若该管道是非阻塞类型,则不论FIFO内是否有数据,读进程都会立即执行读操作。即如果FIFO内没有数据,读函数将立即返回0。

使用FIFO的过程中,当一个进程对管道进行写操作时:

若该管道是阻塞类型,则写操作将一直阻塞到数据可以被写入。

若该管道是非阻塞类型,且不能写入全部数据,则写操作进行部分写入或调用失败。

fifo.c文件
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.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\n", buff);
        }

        printf("*********************** close fifo *************************\n");
  
        close(fd);
        exit(0);
}

void fifo_write(void)
{
        char buff[] = "this is a fifo test demo";
        int fd;
        int nwrite;

        sleep(2);

        fd = open(MYFIFO, O_WRONLY | O_CREAT, 0644);
        if(fd == -1){
                printf("Open fifo file error\n");
                exit(1);
        }

        printf("Write:%s\n", buff);

        nwrite = write(fd, buff, MAX_BUFFER_SIZE);

        // 等待子进程退出
        if(wait(NULL)){
                close(fd);
                exit(0);
        }
}

int main(void)
{
        pid_t pid;

        if((pid = fork()) == 0){
                // 子进程
                fifo_read();
        }else if(pid > 0){
                // 父进程
                fifo_write();
        }else{
                printf("fork error!\n");
        }

        exit(0);
}

Makefile文件

照旧

执行过程

虽使用了父子进程间通信,但即使是没有血缘关系的进程也是一样的操作。

在一个以O_WRONLY(阻塞方式)打开的FIFO中,如果写入的数据长度小于等待PIPE_BUF,则写入全部字节或一个字节也不写入。如果所有的写请求都是发往一个阻塞的FIFO的,并且每个写请求的数据长度小于等于PIPE_BUF字节,字体就可以确保数据绝不会交错在一起。因此支持多用户写入而不会互相干扰

FIFO的应用场景:Linux的日志系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1098531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows连接不上VMware,ping不通的问题

文章目录 防火墙问题Windows和虚拟机下的ip不一致导致的问题VMware Network Adapter (适配器)丢失的问题参考文档 防火墙问题 防火墙默认不会拦截ping命令&#xff0c;除非你个人设置了Linux防火墙Centos7的常用命令关闭防火墙 systemctl stop firewalld #停止Windows和虚拟机…

wordpress遇到的问题

一&#xff09; 403 Forbidden 我是lnmpwordpress&#xff0c;所以在 /etc/nginx/conf.d/default.conf中 修改location 加上 index.php刷新即可&#xff1b; 二&#xff09;wordpress插件更新&#xff0c;需要输入服务器的FTP登录凭证的问题 在 wp-config.php的文件中进行修改…

【C语言】——通讯录(静态-动态增长-文件储存)

目录 前言&#xff1a; 一&#xff1a;整体框架 关于通讯录结构体的创建 二&#xff1a;通讯录的功能实现&#xff08;静态&#xff09; 2.1初始化通讯录 2.2增加联系人 2.3打印通讯录 2.4删除联系人 2.5 查找联系人 2.6修改联系人 2.7排序联系人 三&#xff1a;通…

docker 复习

文章目录 docker 安装配置镜像加速器拉取镜像的仓库&#xff1a; docker 部署Mysql 镜像命令的详细解释docker 相关命令总结 docker 安装 查看是否安装的镜像已经在系统中存在&#xff1a; docker images &#xff08;存在2&#xff0c;不存在 3&#xff09; 卸载旧版本 yum r…

当出现“无法成功完成操作,因为文件包含病毒或潜在的垃圾软件“时的解决办法

安装补丁或其他安装包时,被系统识别为病毒垃圾 具体解决步骤是: 1.在开始菜单&#xff0c;打开Windows 安全中心 找到主页的病毒和威胁防护 找到管理设置 最后将确认安全的文件或安装包添加到排除项即可

Latex 通过\item控制编号

\item通常用于 1 论文写作中的hightlight 2 或一些需要缩进的场景 具体实现 \item 或\item[]在方括号里面添加1&#xff09;、 (1)来控制

Ubuntu系统搭建及环境部署

Ubuntu系统搭建及环境部署 1 制作系统&#xff08;系统盘安装&#xff09;1.1 选择版本&#xff0c;并下载1.2 刻录系统盘1.3 制作系统 2 配置2.1 root登陆2.2 更新国内源 1 制作系统&#xff08;系统盘安装&#xff09; ubuntu中文官网 1.1 选择版本&#xff0c;并下载 在官…

canvas画一个笑脸和画一个三角形

画一个笑脸主要用到的是画弧形的方法&#xff1a;arc&#xff0c;有五个参数&#xff1a;起始坐标&#xff0c;半径&#xff0c;弧形起始坐标&#xff0c;还有一个参数是顺时针还是逆时针。画的笑脸&#xff1a;虽然丑了点&#xff0c;但是学习了 代码&#xff1a; <!DOCTY…

在C++和Python的项目中使用ROS

如果搜索如何使用ROS&#xff0c;搜索结果肯定是先建立工作空间&#xff0c;在创建功能包等等步骤&#xff0c;但其实不需要这么麻烦。 在Python中使用ROS&#xff0c;只需要在Pycharm的Project Structure中的Add Content Root加入ros的packages就可以了&#xff0c;如下图 在…

实时美颜SDK技术的崭新时代:美颜sdk的开发与应用

美颜技术一直以来都备受关注&#xff0c;特别是在社交媒体和直播平台的兴起中&#xff0c;人们对自己的外貌越来越注重。最近这几年&#xff0c;实时美颜已经进入了一个新的阶段&#xff0c;也带来了行业的革新&#xff0c;特别是美颜SDK&#xff0c;在这一进程中扮演了至关重要…

科技与环卫的结合,是智慧公厕厂家的使命

城市&#xff0c;作为人类社会的象征&#xff0c;正经历着前所未有的快速发展和改变。然而&#xff0c;这个发展过程中往往伴随着环境卫生问题&#xff0c;其中城市卫生设施的质量和管理尤为重要。在这个背景下&#xff0c;智慧公厕厂家正致力于将科技与环卫领域的专业知识结合…

牛客周赛 Round 15 D 游游的树上边染红(树形dp)

牛客周赛 Round 15 D 游游的树上边染红(树形dp) 一道很裸的树形dp&#xff0c;周日晚上看了一晚上看不懂&#xff0c;第二天突然就悟了。 题目跟没有上司从舞会很像&#xff0c;我们粗略的考虑&#xff0c;当前节点的状态为选/不选&#xff0c;然后根据此进行状态转移。 不选择…

跨境商城源码有哪些独特的功能和优势

1. 强大的跨境支付功能 跨境商城源码具备强大的跨境支付功能&#xff0c;支持多种支付方式&#xff0c;包括信用卡、支付宝、微信支付等。该功能遵循国际支付标准&#xff0c;能够确保支付过程的安全性和可靠性&#xff0c;为用户提供便捷的跨境购物体验。 2. 多语言和多货币支…

26栈和队列-简单实践

目录 LeetCode之路——20. 有效的括号 分析&#xff1a; LeetCode之路——1047. 删除字符串中的所有相邻重复项 分析&#xff1a; LeetCode之路——20. 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#…

SpringBoot 整和 Netty 并监听多端口

SpringBoot 整和 Netty 并监听多端口 Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架&#xff0c;用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架&#xff0c;Netty 在互联网领域、大数据分布式计算领域…

Bootstrap的警告框组件

可以利用类alert实现警告框组件。。 01-基本的警告框组件使用示例 示例代码如下&#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>警告框</title><meta name"viewport" content"wi…

如何同时打开两个pycharm文件

进入设置&#xff0c;搜索项目&#xff0c;选择新窗口或询问都可以 下面是选择了询问后打开新项目会弹出的页面

Vue进阶(幺陆伍)PhantomJS 实战讲解

文章目录 一、前言二、PhantomJS2.1 PhantomJS 使用场景2.2 PhantomJS 项目实战2.2.1 环境配置2.2.2 Demo: 自动化截图 三、拓展阅读 一、前言 在前期博文《Vue进阶&#xff08;五十六&#xff09;&#xff1a;vue-cli 脚手架 karma.conf.js 配置文件详解》中讲解了 karma.con…

Jmeter关联操作

1.首先右键添加一个线程选择线程组,命名为线程组-1&#xff0c;添加取样器选择HTTP请求--城市天气 2.线程组-1右键&#xff0c;添加取样器选择后置处理器中的JSON提取器 3.线程组-1右键,添加取样器选择后置处理器中的BeanShell 后置处理程序(必须平级) 4.首先右键添加一个线程选…

MySQL学习(一)——简介以及SQL语句

文章目录 1. MySQL介绍1.1 数据库概述1.2 关系型数据库 2. SQL2.1 SQL通用规范2.2 DDL2.2.1 数据库操作2.2.2 创建和查询表2.2.3 修改表2.2.4 数据类型2.2.5 DataGrip使用 2.3 DML2.3.1 添加数据2.3.2 更新和删除 2.4 DQL2.4.1 基础查询2.4.2 条件查询2.4.3 聚合函数2.4.4 分组…