Linux下的管道通信

news2024/10/6 8:25:35

文章目录

  • 无名管道通信
  • 有名管道通信(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;
	}
	else
		printf("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");
    }
    else
        printf("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.coloradmin.cn/o/1057450.html

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

相关文章

【高强度聚焦超声模拟器】模拟分层介质中的高强度聚焦超声波束和加热效应(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

调用gethostbyname实现域名解析(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

手机建模教程 | 如何从易模App中导出模型?有哪些格式?含贴图吗?

很多小伙伴使用易模App是为了能快速地将已有实物的物体“变成”三维模型后转到自己习惯的3D软件中去编辑&#xff0c;于是&#xff0c;大家都关心模型能否导出&#xff0c;以及导出格式有没有自己想要的&#xff1f; 博雅仔告诉大家&#xff0c;当然可以导出&#xff01; 在导出…

阶乘分解质因数

n!中因子p的个数为 枚举n范围内的质数即可 #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std;typedef pair<int, int> PII; typedef long long ll; typedef long double ld;const int N …

手机自动直播系统源码交付与代理加盟注意事项解析!

随着直播行业的不断发展&#xff0c;手机自动直播已经成为了人们生活中不可或缺的一部分。手机无人直播软件成了香饽饽&#xff0c;各类手机实景直播APP大批量涌现。因为创业和技术门槛低&#xff0c;市场需求高&#xff0c;所以成了最火热创业赛道。那么如果是不懂技术的人群&…

【DRAM存储器九】SDRAM介绍-read、write、Precharge、DQM、Power down、Clock Suspend命令

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考资料&#xff1a;《镁光SDRAM数据手册》、《PC SDRAM specification》 目录…

vue中 css scoped原理

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

1004. 最大连续1的个数III(滑动窗口)

一、题目 1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public:int longestOnes(vector<int>& nums, int k) {int mark0;//标记0的个数int MaxLength0;for(int left0,right0;right<nums.size();right){if(nums…

串口数据包收发

数据包 把属于同一批的数据进行打包和分割&#xff0c;方便接收方进行识别 HEX数据包 思路&#xff1a;一个数据规定四个字节&#xff0c;以0xFF为包头&#xff0c;0xFE为包尾&#xff0c;当检测到0xFF时&#xff0c;接下来四个数据就是数据&#xff0c;接收到0xFE时&#x…

计算机视觉——飞桨深度学习实战-图像分类算法原理与实战

基础理论&#xff1a; 图像分类是深度学习在视觉领域第一个取得突破性成果的任务。本章首先介绍了图像分类任务的发展历程与评价指标。然后分为三个角度分别介绍了在图像分类领域具有重要地位的三种模型。第一种是基于残差网络的模型&#xff0c;本章重点介绍了ResNet、DenseN…

PCB铺铜连接方式

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

基于SpringBoot的补习班线上报名系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

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

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

开发中的前端和后端

一、引言 前端和后端是Web开发中两个不同的领域。 前端开发主要负责实现用户界面的设计和功能&#xff0c;包括网页的布局、样式和交互效果。前端开发使用HTML、CSS和JavaScript等技术来构建用户在浏览器中直接与之交互的界面。前端开发人员需要关注网页的可视化效果和用户体验…

【密评】商用密码应用安全性评估从业人员考核题库(三)

商用密码应用安全性评估从业人员考核题库&#xff08;三&#xff09; 国密局给的参考题库5000道只是基础题&#xff0c;后续更新完5000还会继续更其他高质量题库&#xff0c;持续学习&#xff0c;共同进步。 501 多项选择题 《个人信息保护法》要求个人信息处理者应当采取哪些…

[C语言经典100例题-67】(指针解决)输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组

代码 下面是使用指针解决的代码示例&#xff1a; #include <stdio.h>void swap(int *a, int *b) {int temp *a;*a *b;*b temp; }int main() {int arr[100], n, max_index 0, min_index 0;printf("Enter the size of the array: ");scanf("%d"…

堆优化迪氏最短单源路径原理及C++实现

时间复杂度 O(ElogE)&#xff0c;E是边数。适用与稀疏图。 使用前提 边的权为正。可以非连通&#xff0c;非连通的距离为-1。 原理 优选队列&#xff08;小根堆&#xff09;记录两个数据&#xff1a;当前点到源点距离&#xff0c;当前点。先处理距离小的点&#xff1b;如果…

数据在内存中的存储(一个新手的理解)

1.整数在内存中的存储 正整数的原&#xff0c;补&#xff0c;反码都相同。 负整数的三种表示方法各不相同。 提示&#xff1a;负数的反码等于原码符号位不变&#xff0c;其他位置的二进制位取反。 负数的补码等于反码1. 对于整型来说&#xff1a;数据存放在内存中其实存放的是…

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

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

C++(List)

本节目标&#xff1a; 1.list介绍及使用 2.list深度剖析及模拟实现 3.list和vector对比 1.list介绍及使用 1.1list介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;…