Linux下的管道通信

文章目录

  • 无名管道通信
  • 有名管道通信(FIFO)

无名管道通信

无名管道只能用于具有亲缘关系的进程之间的通信,即父子进程或者兄弟进程之间,它是一个半双工的通信模式,具有固定的读端和写端。管道也可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数,但它不是普通文件,并不属于其他任何文件系统,只存在于内存中。
管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1],其中fd[0]固定用于读管道,而fd[1]固定用于写管道。管道关闭时只需将这两个文件描述符关闭即可,可使用普通的close函数逐个关闭各个文件描述符。
一个管道共享了多对文件描述符时,若将其中的一对读写文件描述符都删除,则该管道就失效。
创建管道调用函数pipe来实现,所需要的头文件和函数原型如下。

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

创建成功,函数返回0,创建失败返回-1。
创建无名管道的一个简单例子如下。

#include <unistd.h>
#include <stdio.h>int main()
{int pipe_fd[2];if(pipe(pipe_fd) < 0)  //创建无名管道{printf("Pipe create error.\n");return -1;}elseprintf("Pipe create success.\n");close(pipe_fd[0]);   //关闭管道读描述符close(pipe_fd[1]);   //关闭管道写描述符
}

程序运行后先成功创建一个无名管道,打印创建成功的信息,然后再将其关闭。
用pipe函数创建的管道两端处于一个进程中,由于管道是主要用于在不同进程间通信的,因此这在实际应用中没有太大意义。通常先创建一个管道,再通过fork()函数创建一子进程,该子进程会继承父进程所创建的管道。因此,父子进程分别拥有自己的读写的通道,为了实现父子进程之间的读写,只需把无关的读端或写端的文件描述符关闭即可。
下面的例子是子进程写,父进程读,完整的代码如下。

#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int pipe_fd[2];pid_t pid;   char buf_r[100];char* p_wbuf;int r_num;memset(buf_r,0,sizeof(buf_r));  //初始化内存if(pipe(pipe_fd) < 0)      //创建管道{printf("Pipe create error.\n");return -1;}pid = fork();  //创建一子进程if(pid == 0)   //子进程{close(pipe_fd[0]);   //关闭子进程读描述符sleep(1);     //确保父进程关掉了写描述符if(write(pipe_fd[1],"Hello pipe!",11)!= -1)   //写入管道的是"Hello pipe!"printf("Process write success!\n");close(pipe_fd[1]);  //关闭子进程写描述符exit(0);}else if(pid > 0)  //父进程{close(pipe_fd[1]);    //关闭父进程写描述符if((r_num = read(pipe_fd[0],buf_r,100)) > 0){printf("length : %d   string : %s\n",r_num,buf_r);} close(pipe_fd[0]);  //关闭父进程读描述符 exit(0);}
}

程序运行后的结果如下图所示。
在这里插入图片描述
父子进程在运行时,它们的先后次序并不能保证,因此,为了保证父进程已经关闭了读描述符,可在子进程中调用sleep函数。


有名管道通信(FIFO)

无名管道只能用于具有亲缘关系的进程之间,这就大大地限制了管道的使用。有名管道的出现突破了这种限制,它可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作,使用非常方便。不过值得注意的是,FIFO是严格地遵循先进先出规则的,对管道及FIFO 的读总是从开始处返回数据,对它们的写则把数据添加到末尾。
有名管道的创建可以使用函数mkfifo(),在创建管道成功之后,就可以使用open、read、write这些函数了。对于为读而打开的管道可在open中设置O_RDONLY,对于为写而打开的管道可在open中设置O_WRONLY,这里与普通文件不同的是涉及阻塞的问题。由于普通文件的读写时不会出现阻塞问题,而在管道的读写中却有阻塞的可能,这里的非阻塞标志可以在open函数中设定为O_NONBLOCK。
对于读进程,若该管道是阻塞打开,且当前FIFO内没有数据,则对读进程而言将一直阻塞直到有数据写入。若该管道是非阻塞打开,则不论FIFO内是否有数据,读进程都会立即执行读操作。
对于写进程,若该管道是阻塞打开,写进程将一直阻塞直到有读进程读出数据。若该管道是非阻塞打开,即使当前FIFO内没有读操作,写进程都会立即执行读操作。
简单来说,阻塞方式就是要等另一方先执行,非阻塞方式则不会考虑另一方的状态。
创建有名管道调用函数mkfifo来实现,所需要的头文件和函数原型如下。

#include <sys/types.h>
#include <sys/state.h>
int mkfifo(const char *filename,mode_t mode)

创建成功,函数返回0,创建失败返回-1。
下面的例子包含一个读管道和一个写管道,在读管道里面创建管道,用户输入的内容以写管道里main函数的参数传入,然后读管道读出管道的内容。
read.c文件的内容如下。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"   //定义路径int main(int argc,char** argv)
{char buf_r[100];int fd;int nread;if((mkfifo(FIFO,O_CREAT|O_EXCL) < 0) && (errno!=EEXIST))  //创建有名管道,O_CREAT文件不存在时创建,O_EXCL如果使用O_CREAT时文件存在,那么可返回错误消息printf("Create FIFO failed.\n");printf("Preparing for reading bytes...\n");memset(buf_r,0,sizeof(buf_r));    //初始化内存fd = open(FIFO,O_RDONLY|O_NONBLOCK,0);    //打开有名管道,非阻塞方式//fd = open(FIFO,O_RDONLY,0);        //打开有名管道,阻塞方式if(fd == -1){perror("Open");exit(1);}while(1){memset(buf_r,0,sizeof(buf_r));if((nread = read(fd,buf_r,100)) == -1){if(errno == EAGAIN)printf("No data yet.\n");}printf("String read from FIFO is %s\n",buf_r);sleep(1);  //设置读管道的速度}pause();  //将调用进程挂起直至捕捉到信号为止,通常可以用于判断信号是否已到unlink(FIFO);
}

write.c文件的内容如下。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"int main(int argc,char** argv)  //argc是传入参数的个数,argv[0]为自身运行目录路径和程序名,argv[1]存放的是用户输入
{int fd;char w_buf[100];int nwrite;if(fd == -1)if(errno == ENXIO)printf("Open error, no reading process.\n");fd = open(FIFO,O_WRONLY|O_NONBLOCK,0);  //打开FIFO管道,并设置非阻塞标志//fd = open(FIFO,O_WRONLY,0);  //打开FIFO管道,并设置阻塞标志if(argc == 1)printf("Please send string.\n");strcpy(w_buf,argv[1]);if((nwrite=write(fd,w_buf,100))==-1)   //向管道中写入字符串{if(errno==EAGAIN)printf("The FIFO has not been read yet, please try later.\n");}elseprintf("String write to the FIFO is %s\n",w_buf);
}

打开两个终端,编译后先执行read,后执行write,因为read要先创建管道,read执行时如果没有权限就加sudo执行,如下图所示。
在这里插入图片描述
然后在执行write时需要带上用户的输入,也就是需要写入的内容。
在这里插入图片描述
这样就实现了有名管道的通信。
需要注意的是,如果一开始就使用sudo执行read的话,所创建的管道在write的时候也需要加sudo,否则无法通信。因为 sudo ./read执行时创建的管道文件的所有者和组都是root,write执行时无权访问,要不就加sudo,要不就使用chown和chgrp命令修改管道文件的所有者。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudAlibaba 相关组件的学习一

目录 前言 系统架构演变 1、单体架构 2、垂直架构 3、分布式架构 4、SOA架构 5、微服务架构 一、微服务架构的介绍 1、微服务架构的常见问题 2 微服务架构的常见概念 2.1 服务治理 2.2 服务调用 2.3 服务网关 2.4 服务容错 2.5 链路追踪 3、微服务架构的常用解决…

自定义实现hashmap-python

前文 ​ 今天这篇文章给大家讲讲hashmap&#xff0c;这个号称是所有前后端工程师都会的数据结构。 hashmap基本结构 ​ hashmap这个数据结构其实并不难&#xff0c;它的结构非常清楚&#xff0c;说白了就是一个定长的链表&#xff0c;这个数组的每一个元素都是一个链表。我们…

司空见惯 - 奈尔宝的NTTP

联合国对21世纪人才定义的标准&#xff0c;包括六种核心技能&#xff0c;即批判性思维&#xff08;critical thinking)、人际交往&#xff08;communication)、与人合作&#xff08;collaboration)、创造性&#xff08;creativity)、信息素养&#xff08;information literacy)…

DPDK程序结合网络助手接收数据

网络调试工具&#xff1a;https://download.csdn.net/download/hdsHDS6/88390999?spm1001.2014.3001.5503 DPDK代码&#xff1a; #include <stdio.h> #include <string.h> #include <rte_eal.h> #include <rte_ethdev.h> #include <rte_ip.h> …

【数据结构】红黑树(C++实现)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【数据…

特斯拉被称为自动驾驶领域的苹果

特斯拉的自动驾驶技术无疑是居于世界上领先地位的,有人形容特斯拉是自动驾驶汽车领域的苹果。特斯拉发布的Tesla Vision系统只配备了摄像头,不依靠雷达。 这并不是特斯拉唯一和其它对手不同的地方,他们的整个战略都是基于车队和销售产品,而其大多数竞争对手则销售自…

对象创建与内存分配机制

对象的创建 对象创建的主要流程: 1.类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类…

stm32 - 中断/定时器

stm32 - 中断/定时器 概念时钟树定时器类型基准时钟&#xff08;系统时钟&#xff09;预分频器 - 时基单元CNT计数器 - 时基单元自动重装寄存器 - 时基单元基本定时器结构通用定时器计数器模式内外时钟源选择 定时中断基本结构时序预分频器时序计数器时序 概念 时钟树 https:…

解决Invalid bound statement (not found)错误~

报错如下所示&#xff1a; 找了好久&#xff0c;刚开始以为是名称哪里写的有问题&#xff0c;但仔细检查了好多遍都不是 最后发现了问题如下所示&#xff1a; UserMapper里面的内容被我修改了&#xff0c;但classes中的内容还是原来的内容&#xff0c;所以才导致了编译器报错n…

Android 活动Activity

目录 一、启停活动页面1.1 Activity的启动和结束1.2 Activity的生命周期1.3 Activity的启动模式 二、在活动之间传递消息2.1 显式Intent和隐式Intent2.2 向下一个Activity发送数据2.3 向上一个Activity返回数据 三、补充附加信息3.1 利用资源文件配置字符串3.2 利用元数据传递配…

【Python】函数(function)和方法(method)的区别

这里先说结论&#xff0c;为了满足心急的小伙伴&#xff1a;method与function的最大区别就是参数有无进行绑定。 自定义类Test&#xff1a; 首先先来一个自定义类&#xff1a; class Test:def Func_normal(arg):print(Func_normal:,arg)staticmethoddef Func_static(arg):pri…

sentinel-dashboard-1.8.0.jar开机自启动脚本

启动阿里巴巴的流控组件控制面板需要运行一个jar包&#xff0c;通常需要运行如下命令&#xff1a; java -server -Xms4G -Xmx4G -Dserver.port8080 -Dcsp.sentinel.dashboard.server127.0.0.1:8080 -Dproject.namesentinel-dashboard -jar sentinel-dashboard-1.8.0.jar &…

【小尘送书-第六期】《巧用ChatGPT轻松玩转新媒体运营》AI赋能运营全流程,帮你弯道超车、轻松攀登运营之巅

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…

1.5 计算机网络的类别

思维导图&#xff1a; 1.5.1 计算机网络的定义 我的笔记&#xff1a; #### 精确定义&#xff1a; 计算机网络没有统一的精确定义&#xff0c;但一种较为接近的定义是&#xff1a;计算机网络主要由一些通用的、可编程的硬件互连而成&#xff0c;这些硬件并非专门用来实现某一特…

【软件测试】自动化测试selenium(一)

文章目录 一. 什么是自动化测试二. Selenium的介绍1. Selenium是什么2. Selenium的特点3. Selenium的工作原理4. SeleniumJava的环境搭建 一. 什么是自动化测试 自动化测试是指使用软件工具或脚本来执行测试任务的过程&#xff0c;以替代人工进行重复性、繁琐或耗时的测试活动…

vue中 css scoped原理

Vue中css的逻辑是先放子组件&#xff0c;然后放父组件&#xff0c;所以同样的css类名&#xff0c;子组件会被父组件覆盖 html 如下 子被父覆盖 scoped是通过给组件加hash值&#xff0c;锁定组件。 父子组件均scoped的情况下&#xff0c;子仍会覆盖 还是被覆盖了 如何避免被…

Springboo整合Sentinel

Springboo整合Sentinel 1.启动Sentinel java -jar sentinel-dashboard-1.8.6.jar2.访问localhost:8080到Sentinel管理界面(默认账号和密码都是sentinel) 3.引入依赖(注意版本对应) <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spr…

[Linux] 5.Linux虚拟机和Windows文件共享

一、拖拽 如果安装了VMware Tool可以从Windows直接拖进Linux中共享文件&#xff0c;通过拖拽的方式可以把文件从Linux 传输到Windows 二、 文件共享 需要安装VMware Tool点击添加&#xff0c;选择Windows文件的路径&#xff0c;名称作为Linux访问的路径 cd什么都不加&#xff…

PCB铺铜连接方式

在铺铜前先把栅格吸附关闭铺铜会流畅很多 在嘉立创专业版中&#xff0c;默认铺铜方式是这样 改变铺铜规则为直连 效果如下

leetCode 55.跳跃游戏 贪心算法

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入…