linux系统进程间通信方式(三):管道

2023-05-16

进程间通信方式之管道

管道通常指无名管道(PIPE)或有名管道(FIFO),但实际上套接字也都是管道。

接口

PIPE和FIFO的相关接口如下表格

功能创建无名管道:PIPE说明
头文件#include <unistd.h>
原型int pipe(int pipefd[2]);
参数pipefd一个至少具有2个int型数据的数组,用来存放PIPE的读/写端描述符
返回值成功0
失败-1
功能创建有名管道:FIFO
头文件#include<sys/types.h>
#include <sys/stat.h>
原型int mkfifo(const char *pathname, mode_t mode);
参数pathnameFIFO的文件名
mode文件权限
返回值成功0
失败-1

PIPE(匿名管道)

先来看看PIPE。既然叫管道,那么可以想象它就像一根水管,连接两个进程,一个进程要给另一个进程数据,就好像将水灌进管道一样,另一方就可以读取出来了,反过来也一样。

先来罗列pipe的特征:

(1)没有名字,因此无法使用open()

(2)只能用于亲缘进程间(如父子进程、兄弟进程、祖孙进程等)通信

(3)半双工工作方式:读写端分开

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

(5)不能使用lseek()来定位

PIPE是一种特殊的文件,但虽然他是一种文件,却没有名字。因此,一般进程无法使用open()函数来获取它的描述符,它只能在一个进程中被创建出来,然后通过继承的方式将它的描述符传递给子进程,这就是为什么PIPE只能用于亲缘进程间通信的原因。

另外,PIPE不同于一般文件的显著之处:它有两个描述符,一个只能用来读,另一个只能用来写,这就是所谓的“半双工”通信方式。再一个显著的弱项:它对写操作不做任何保护。即使有多个进程或线程同时对PIPE进行写操作,那么这些数据很有可能会相互践踏,因此一个简单的结论是:PIPE只能用于一对一的亲缘进程通信。最后,PIPE与FIFO、socket一样,这些管道文件都不能使用lseek()来进行所谓的定位,因为它们的数据不像普通数据那样按块的方式存放在如硬盘、flash等块设备上,而更像一个看不见源头的水龙头,所以无法定位。

下面代码展示了子进程如何通过PIPE向父进程发送一段数据。

pipe.c

//

//  Description: 使用无名管道pipe,实现父子进程间通信

//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
	int fd[2];

	if(pipe(fd) == -1)
	{
		perror("pipe()");
		exit(1);
	}

	pid_t x = fork();

	if(x == 0)
	{
		char *s = "hello, I am your child\n";
		write(fd[1], s, strlen(s));
	}
	
	if(x > 0)
	{
		char buf[30];
		bzero(buf, 30);

		read(fd[0], buf, 30);
		printf("from child: %s", buf);
	}

	close(fd[0]);
	close(fd[1]);
	return 0;
}

父进程必须先创建PIPE,然后再创建子进程,这样子进程才能继承父进程已经产生的PIPE的文件描述符。

从上述代码中可以看到,实际上父进程并没有使用PIPE的写端描述符fd[1],同理子进程也没有使用PIPE的读端描述符fd[0],所以其实它们是可以被关闭,也是应该被关闭的。

FIFO(有名管道)

任何事物的优缺点都是相对的,PIPE很简单,同时也适用于场景比较单一、性能比较弱、限制条件比较多的场合;如果要在任意进程间通信,并且保证写入有原子性,那么我们可以使用FIFO。

有名管道FIFO的特征如下:

(1)有名字,存储于普通文件系统之中

(2)任何具有相应权限的进程都可以使用open()来获取FIFO的文件描述符

(3)跟普通文件一样,使用统一的read()/write()来读写

(4)跟普通文件不同:不能使用lseek()来定位

(5)写入具有原子性,支持多写者同时进行写操作而数据不会互相践踏

(6)First In First Out,最先被写入的数据,最先被读出来

下面通过一段最简单的示例代码,展示两个普通进程(Jack、Rose)如何通过FIFO互相传递信息:Jack从键盘接收一段输入并发送给Rose,Rose接收数据之后将其显示到屏幕上。

head4fifo.h

#ifndef _HEAD4FIFO_H_
#define _HEAD4FIFO_H_

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

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

#define FIFO "/tmp/fifo4test"

#endif

Jack.c

//


//  Description: 使用命名管道FIFO,实现两个进程间通信

//

#include "head4fifo.h"

int main(int argc, char **argv)
{
	if(access(FIFO, F_OK))
	{
		mkfifo(FIFO, 0644);
	}

	int fifo = open(FIFO, O_WRONLY);
	
	char msg[20];
	bzero(msg, 20);

	fgets(msg, 20, stdin);
	int n = write(fifo, msg, strlen(msg));

	printf("%d bytes have been sended.\n", n);
	return 0;
}

Rose.c

//
  
//  Description: 使用命名管道FIFO,实现两个进程间通信

//

#include "head4fifo.h"

int main(int argc, char **argv)
{
	if(access(FIFO, F_OK))
	{
		mkfifo(FIFO, 0644);
	}

	int fifo = open(FIFO, O_RDONLY);
	
	char msg[20];
	bzero(msg, 20);

	read(fifo, msg, 20);
	printf("from FIFO: %s", msg);

	return 0;
}

注意以下几点:

(1)代码第5行中的函数access()通过指定参数F_OK来判断一个文件是否存在,另外还可以通过别的参数来判断文件是否可读、可写、可执行等。

(2)当刚开始运行Jack而尚未运行Rose,或是刚开始运行Rose尚未运行Jack时,open函数会被阻塞,因为管道文件(包括PIPE、FIFO、SOCKET)不可以在只有读端或只有写端的情况下被打开

(3)当Jack已经打开但还没写入数据之前,Rose将在read()上阻塞睡眠,直到Jack写入数据完毕为止。因为默认状态下是以阻塞方式读取数据的,可以使用fcntl()来使得FIFO变成非阻塞模式。

不仅打开管道会有可能发生阻塞,在对管道进行读/写操作时也有可能发生阻塞,可以参考下面的表格。

所谓写者:持有文件可写权限描述符的进程

所谓读者:持有文件可读权限描述符的进程

在这里插入图片描述

FIFO与PIPE还有一个最大的不同点在于:FIFO具有一种所谓写入原子性的特征,这种特征使得我们可以同时对FIFO进行写操作而不怕数据遭受破坏,一个典型的应用时linux的日志系统。

系统的日志信息被统一安排存放在/var/log下,这些日志文件都是一些普通的文本文件。普通文件可以被一个或多个进程重读多次打开,每次打开都有一个独立的位置偏移量,如果多个进程或线程同时写文件,那么除非它们之间能相互协调好,否则必然导致混乱。

事实上:需要写日志的进程根本不可能“协调好,系统日志实际上就相当于一个公共厕所,系统中阿猫阿狗都可以进去拉撒一通,由于写日志的进程是毫无关联的,因此常用的互斥手段(如互斥锁、信号量等)是无法起作用的,就好像无法试图通过交通规则来杜绝有人乱闯红灯一样,因为总有人可以故意无视规则,肆意践踏规则。

如何使得毫不相干的不同进程的日志信息都能完整地输送到日志文件中而不相互破坏,是一个必须解决的问题。一个简单高效的方案是:使用FIFO来接收各个不相干进程的日志信息,然后让一个进程专门将FIFO中的数据写到相应的日志文件中。这样做的好处是:任何进程无需对日志信息的互斥编写出任何额外的代码,只管向FIFO里面写入即可。后台默默耕耘的日志系统服务例程会将这些信息一一地拿出来再写入日志文件,FIFO的写入原子性保证了数据的完整无缺。

总结

本文详细介绍了匿名管道和有名管道这两个用于进程间通信的方式,并总结了他们的特点和使用场景;也通过示例演示了两个进程如何通过管道进行通信,对管道这种通信方式有了更深刻的理解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux系统进程间通信方式(三):管道 的相关文章

  • ORB-SLAM2的布置(二)ORB-SLAM2的安装

    当在上一节中 xff0c Pangolin 安装成功后 xff0c 便可进行ORB SLAM2的安装 这里的普通模式是指直接运行编译之后的可执行文件 xff0c ROS 模式是以ROS机器人框架的形式执行 首先从 github 下载源文件
  • ORB-SLAM2的布置(四)ORB-SLAM2构建点云

    提要 高博的工作是对基本 ORB SLAM2 的扩展 xff0c 基本思想是为每个关键帧构造相应的点云 xff0c 然后依据从 ORB SLAM2 中获取的关键帧位置信息将所有的点云拼接起来 xff0c 形成一个全局点云地图 https g
  • ORB-SLAM2的布置(三)ORB-SLAM2的测试使用

    目标 在上一节 xff0c 我们完成了ORB SLAM2的编译与测试 xff0c 这一节使用完整的数据集进行测试 普通模式 这里的普通模式直接运行编译之后的可执行文件 单目摄像头 首先是单目摄像头 这里我们使用TUM数据集进行离线测试 去到
  • ORB-SLAM2的布置(五)使用 intel D435i 构建SLAM点云地图

    Intel RealSense SDK 2 0 是跨平台的开发套装 xff0c 包含了基本的相机使用工具如 realsense viewer xff0c 也为二次开发提供了丰富的接口 xff0c 包括 ROS xff0c python Ma
  • 阿里云ecs服务器(Ubuntu)配置图形界面并远程桌面连接

    1 登录阿里云后跳转到管理页面 xff0c 点击远程连接 xff08 如图1 xff09 2 选择Workbench远程连接登录进入到终端命令窗口 xff0c 首次登录需要设置实例密码 登录后界面如下 3 安装ubuntu桌面系统 执行下面
  • Windows Nodejs多版本使用

    一 遇到的问题 不同的项目使用的node版本不一致 xff0c 导致使用的时候 xff0c 安装依赖的时候冲突了 xff0c 从网上找了很多的方案 xff0c 解决起来也挺费劲的 xff1b 问题 xff1a 当一个项目使用低版本的时候 x
  • linux 自平衡AVL树

    简介 仔细观察BST会发现 xff0c 虽然它有良好的 搜索 特性 xff0c 也就是可以利用其节点之前的大小关系 xff0c 很容易地从根节点开始往下走找到我们所要的节点 xff0c 但它无法保证这种搜索所需要的时间长短 xff0c 因为
  • C++职业发展路线

    一 C 43 43 服务器程序员 xff08 流媒体后台 xff0c 游戏后台 xff0c 高性能服务器后台 xff09 精通C 43 43 xff0c STL xff0c Linux等 xff0c 熟悉设计模式 xff1b 熟练掌握一门脚
  • Apache CXF文件目录结构及需要jar包

    原文地址 xff1a http blog 163 com a13151055695 64 126 blog static 112087074201143014443273 文件目录结构及相关文件的详细说明 xff1a bin xff08 目
  • 浅析SAX,DOM,JAXP,JDOM与DOM4J之间的关系

    众所周知 xff0c SAX与DOM是JAVA中两大核心XML解析API类库 xff0c 而JAXP JDOM与DOM4J都是基于这两大核心API而衍生出来的 今日兴起看了看相关资料 xff0c 在这里总结总结 SAX与DOM 首先需要说明
  • StAX-基于流的拉式XML解析

    最近在学习webservice时 xff0c 发现很多框架 xff0c 技术都在使用StAX作为底层XML解析工具 xff0c 于是今天看了看资料 xff0c 简单学习了下 xff0c 在这里做个总结 简介 StAX xff0c 全称 St
  • 那些支持我学习与工作的良师益友

    2011大学毕业后 xff0c 成为一名JAVA开发人员从事开发工作只有区区3年不到的时间 回想高中时 xff0c 学校计算机课开设Flash课程 xff0c 第一次接触Flash的我 xff0c 便对计算机技术产生了浓厚的兴趣 xff0c
  • Apache HttpClient4.2入门

    介绍 HttpClient 是 Apache Jakarta Common 下的子项目 xff0c 用来提供高效的 最新的 功能丰富的支持 HTTP 协议的客户端编程工具包 xff0c 并且它支持 HTTP 协议最新的版本和建议 HttpC
  • JMX “javax.management.NotCompliantMBeanException” 异常解决

    原文章 xff1a http lovespss blog 51cto com 1907593 616403 昨天同事在JBoss中部署MBean时一直报错 xff1a Caused by javax management NotCompli
  • webservice-WSDL结构与各元素解析

    承接上一遍webservice初识 xff0c 这篇文章将着重于WSDL wsdl协议说明http www w3 org TR wsdl 结构 现在开始说说wsdl的结构以及各个元素的意义 从下面这张图可以看出wsdl中各元素是存在嵌套的关
  • alsa amixer 使用介绍

    alsa utils 提供的工具中 xff0c arecord 可以用来录音 xff0c aplay 可以用来播放 xff0c amixer 可以用来控制音量 增益等 amixer controls numid 61 34 iface 61
  • C# 自定义控件制作和使用实例

    C 自定义用户控件 xiongxuanwen 上篇 xff1a 控件制作 本例是制作一个简单的自定义控件 xff0c 然后用一个简单的测试程序 xff0c 对于初学者来说 xff0c 本例子比较简单 xff0c 只能起到抛石引玉的效果 我也
  • 二叉树搜索性能比较

    二叉树搜索性能分析 我想测试一下不同类型的二叉树搜索数据的性能是什么样的 众所周知 xff0c 二叉树有以下几种类型 xff1a BSTAVL红黑树 对于搜索数据 xff0c 具体来讲 xff0c 当树保持平衡时 xff0c 其搜索时间复杂
  • Kubernetes系统架构

    控制单元 xff1a kube apiserver xff1a 所有客户端通过kube apiserver访问cluster中的各种服务 xff0c 资源以及应用 etcd xff1a 键值对数据库 xff0c 存放所有的集群数据 kube
  • Kubernetes的网络模型(K8S集群中的三个网络)

    一个K8S的集群中至少有三个网络 xff1a 1 集群节点所在的网络 xff0c 这个网络就是你的主机所在的网络 xff0c 通常情况下是你的网络基础设施提供 如果你的node处于不同的网段 xff0c 那么你需要保证路由可达 如上图中的

随机推荐

  • K8S中的容器(Container)之间的网络接口

    Kubernetes集群中当一个容器启动时 xff0c 容器里面会启动一个以太网络接口 xff08 eth0 xff0c 分配的是Pod网络所用的IP地址 xff0c 通过一个虚拟以太网对 xff08 veth pair xff0c 连接到
  • K8S中Pod之间互相访问,外部访问如何访问Pod的网络连接原理

    Pod中的Container启动时 xff0c 会分配一个Pod网段中的IP地址 xff08 network cidr xff09 xff0c 但是这个IP地址是浮动的 xff08 ephemeral xff09 xff0c Pod重启 x
  • kubectl proxy 是什么

    大家都知道 xff0c 在K8S集群中的业务从外部默认是不能访问的 xff0c 正式环境中 xff0c 我们需要通过service xff0c 然后通过Node的ip地址和Loadbanlencer来访问 但是还有一些简单的方式 xff0c
  • kubectl port-forward命令访问集群中业务

    使用kubectl proxy可以访问Pod中的业务 xff0c 但是URL要加上namespace xff0c service等 xff0c 比较长 kubectl还提供了一个功能 xff0c 就是kubectl port forward
  • K8S服务发现(kube-dns) : CoreDNS

    K8S中 xff0c Pod如果想也另外一个Pod通信 xff0c 通常不会直接基础此Pod的IP xff08 动态的 xff09 xff0c 也不会记住此Pod形成的Service的IP xff08 相对比较稳定 xff0c 但也是动态的
  • Git 主干分支模型中的CI、CD ( 一)

    分支模型 主干分支模型如上图 xff0c 项目有个主干分支和若干个release分支 主干分支 xff1a 开发人员在主干分支上 xff08 通常情况下是master分支 xff09 push代码 xff0c push代码签需要在本地做re
  • Git主干分支模型中的CI、CD ( 二)

    分支模型 如果主干分支随意push引起较大的混乱 xff0c 可以考虑么个人开发是创建一个临时feature分支 如下图 xff1a 主干分支模型如上图 xff0c 项目有个主干分支和若干个release分支 xff0c 还有一些临时的fe
  • 持续集成CI, 持续发布CD,持续部署CD的意义及区别

    持续集成 xff0c 持续发布 xff0c 持续部署是自动化release pipeline的三个阶段 xff0c 通过这三个阶段 xff0c 团队把软件从创意 xff0c 生产为软件 xff0c 并发布给终端用户 这三个阶段关注产品的三个
  • linux系统常用命令总结

    简介 本文简单记录常用的linux系统shell命令 命令 linux系统常用shell命令如下表格 命令功能示例备注alias给命令起别名alias c 61 clear 取clear的别名为ccat显示文本内容cat file显示fil
  • 持续集成:CI

    持续集成 xff0c 持续发布 xff0c 持续部署是DevOps中三个实现手段很相似 xff0c 但是应用场景不同的三个概念 我接下来主要从应用场景来描述一下这三个场景的主要关注点 持续集成 xff1a 发生在开发阶段 xff0c 开发人
  • 持续发布(CD Continuous Deployment)

    持续发布是持续集成的延续 每次当我的代码被push到代码仓库后 xff0c 业务也应该被持续部署 如果使用持续发布 xff08 CD xff09 xff0c 发布过程是手动触发的 CD可以自动检查代码变化 xff0c 但是必须需要人工干预
  • 持续部署(CD, Continuous Deployment)

    持续也是持续集成的扩展 xff0c 和持续发布一样 xff0c 不同的是持续部署不需要手动干预 xff0c 直接自动部署到生产环境
  • Git中Feature分支模型中的CI,CD

    分支模型 主干分支 Master xff1a 随时可供在生产环境中部署的代码 xff0c 建议伴有标签 xff08 TAG xff09 Develop xff1a 每天需要提交和合并的代码 xff0c 功能逐渐完成的代码开发分支 辅助分支
  • DevSecOps及软件IT安全防护的开源扫描工具

    最近研究了一下热门话题 xff1a DevSecOps xff0c 明白了不少网络安全方面的概念和不少顶级的开源安全扫描工具 xff0c 现分享给大家 过去 xff0c 每个公司有一个信息安全防护的部门 xff0c 专门负责公司的IT信息安
  • K8S服务发现(kube-dns)

    K8S中 xff0c Pod如果想也另外一个Pod通信 xff0c 通常不会直接基础此Pod的IP xff08 动态的 xff09 xff0c 也不会记住此Pod形成的Service的IP xff08 相对比较稳定 xff0c 但也是动态的
  • K8S中的负载均衡Ingress

    K8S通过Ingress xff0c 把K8S集群中的服务 xff0c 通过Http和https路由暴露给外部用户 路径等信息通过Ingress的资源文件配置 1 一个K8S集群 2 一个集群Admin xff0c 两个个K8S用户 Use
  • DevOps关键指标

    不能衡量 xff0c 就无法管理 xff1b 不能管理 xff0c 就无法改进 xff0c 这句话对于DevOps或其它研发管理实践来说 xff0c 是正确的 为了实现DevOps的承诺 xff1a 更快地交付更高质量的产品 xff0c D
  • 成功的CEO的特质(一个投资人的观察)

    一个投资人总结他投资的100多个成功创业者的特质 1 不需要外部驱动 xff0c 不需要钱 危机状况触发他们的斗志 xff0c 他们内心有者强烈的驱动力 xff0c 证明自己的想法是对的 xff0c 能让世界变得更好 即使他们变得很富有了也
  • minikube 及安装

    和 kind 一样 xff0c minikube是一个在PC机上本地部署单节点Kubernetes集群的工具 xff0c 可以作为K8S的学习 xff0c 测试环境 在linux上安装minikube xff1a span class to
  • linux系统进程间通信方式(三):管道

    进程间通信方式之管道 管道通常指无名管道 xff08 PIPE xff09 或有名管道 xff08 FIFO xff09 xff0c 但实际上套接字也都是管道 接口 PIPE和FIFO的相关接口如下表格 功能创建无名管道 xff1a PIP