IPC 管道 Linux环境

news2024/11/29 14:53:28

管道通信的特点:

1. 单工通信---- 任何一个时刻只能发送方 向 接收方发送数据

2. 流式传输:

    1> 先发送的数据先被接收,不能跳跃式接收 ----- 顺序发送顺序接收
    2> 未被接收的数据仍然滞留在管道中,下一次可以继续接收后续
    3> 已被接收的数据不会再出现管道中

3. 发送接收次序:

按被发送数据所占空间的地址值从小到大依次发送,接收到数据按次序依次存放在目标空间的从小到大的地址位置

Linux支持的管道有两种:

1. 匿名管道:

无名管道,只能用在具备亲缘关系的进程间命名管道:

2. 有名管道,

可以用在任意进程间,采用管道文件名给一个管道命名


1. 匿名管道

适用于具有亲缘关系的进程间

父进程向子进程发送数据的代码模板:

int arrfd[2] = {-1,-1};
pid_t pid;

pipe(arrfd);

pid = fork();
if(pid > 0){ //父进程才执行的代码
	close(arrfd[0]);
	//用arrfd[1]发送数据 ------ write(fd,...,...)
	close(arrfd[1])//无需继续发送时,及时调用
}
else if(pid == 0){//子进程才执行的代码
	close(arrfd[1]);
	//用arrfd[0]接收数据 ----- read(fd,...,...)
	close(arrfd[0])//无需继续接收时,及时调用
}
.......

子进程向父进程发送数据的代码模板:

int arrfd[2] = {-1,-1};
pid_t pid;

pipe(arrfd);

pid = fork();
if(pid > 0){ //父进程才执行的代码
	close(arrfd[1]);
	//用arrfd[0]接收数据 ----- read(fd,...,...)
	close(arrfd[0])//无需继续接收时,及时调用
}
else if(pid == 0){ //子进程才执行的代码
	close(arrfd[0]);
	//用arrfd[1]发送数据 ------ write(fd,...,...)
	close(arrfd[1])//无需继续发送时,及时调用

}
.......
管道读写数据的特点:

匿名、命名通用

管道中无数据可读时,read函数会阻塞

管道中数据已满时,write函数会阻塞

read函数返回0时,表示写端已关闭,不会有后续数据可接收


e.g.

#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc,char *argv[]){
    pid_t pid;
    int fds[2] = {-1,-1};
    int ret = 0;

    ret = pipe(fds);
    if(ret){
        printf("pipe error\n");
        return 1;
    }

    pid = fork(); // fork

    if(pid < 0){
        printf("fork error\n");
        return 2;
    }
    if(pid > 0){
        close(fds[0]); // 关掉读
        fds[0] = -1;
        write(fds[1],"hello",6); // write
        close(fds[1]); // 关掉写
        fds[1] = -1;
    }
    else{ // 子进程
        char buf[8] = "";
        close(fds[1]); // 关掉写
        fds[1] = -1;
        read(fds[0],buf,8); // read
        printf("In child process,buf = %s\n",buf);
        close(fds[0]); // 关掉读
        fds[0] = -1;
    }
    return 0;
}

输出:


2. 命名管道

匿名管道没有名字,pipe 函数直接获得两端描述符,然后进行接收发送

匿名管道只能借助于 fork 函数传递同一管道的描述符,因此只能用于具有亲缘关系的进程间

命名管道也称为有名管道

命名管道用管道文件名作为它的名字,因此创建命名管道时需要指定这个文件名,然后以两种不同的方式打开这个文件获得两端描述进行接收发送

只要两个进程操作的是同一个管道文件,即可通过该管道文件代表的管道进行通信,因此进程间没必要具有亲缘关系


创建函数:mkfifo

打开函数: open ------ 见系统IO

获得读端描述符:open(管道文件名,O_RDONLY);

获得写端描述符:open(管道文件名,O_WRONLY);

发送数据函数:write ---- 见系统IO

配合open(管道文件名,O_WRONLY)得到的描述符

接收数据函数:read ------ 见系统IO

配合 open (管道文件名,O_RDONLY) 得到的描述符

关闭函数:close ------ 见系统IO


使用命名管道的基本套路:

#define FIFO_NAME "/tmp/myfifo"
发送进程:

if(access(FIFO_NAME,F_OK)){//文件不存在,意味着命名管道未被创建
	mkfifo(....);
}

 ? = open(FIFO_NAME,O_WRONLY);

调用write函数发送数据

close ----- 无需继续发送数据时及时调用


接收进程:
if(access(FIFO_NAME,F_OK)){//文件不存在,意味着命名管道未被创建
	mkfifo(....);
}

? = open(FIFO_NAME,O_RDONLY);

调用read函数接收数据

close ----- 无需继续接收数据时及时调用


p.s.

write_process.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int wfd = -1;

    if(argc < 2){
        printf("The argument is too few\n");
        return 1;
    }

    if(access(argv[1],F_OK)){ // 如果argv[1]存在,access为0
        mkfifo(argv[1],0666); // 0666为使用权限
    }
    wfd = open(argv[1],O_WRONLY);
    if(wfd < 0){
        printf("w-open %s failed\n",argv[1]);
        return 2;
    }
    write(wfd,"hello",6);
    close(wfd);
    wfd = -1;
    return 0;
}

read_process.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int rfd = -1;
    char buf[8] = "";
    if(argc < 2){
        printf("The argument is too few\n");
        return 1;
    }

    if(access(argv[1],F_OK)){ // 如果argv[1]存在,access为0
        mkfifo(argv[1],0666); // 0666为使用权限
    }
    rfd = open(argv[1],O_RDONLY);
    if(rfd < 0){
        printf("r-open %s failed\n",argv[1]);
        return 2;
}
    read(rfd,buf,6);
    printf("buf:%s\n",buf);
    close(rfd);
    rfd = -1;
    return 0;
}

p.s.

运行其中一个程序:发现程序堵塞 (堵塞在open处而不是read/write处)

创建新标签页,运行另一个程序:

程序成功输出


3. 通信协议的制定

        任何通信形式,首先必须为参与通信的各方制定统一的规则,这种规则被称为通信协议(protocol)。

一份通信协议至少包括如下内容:

1. 交互的数据种类、作用
2. 每种数据的二进制位组成(统称为数据格式)
        按协议组织好的一种通信数据,被称为PDU(Protocol Data Unit)
3. 区分数据种类的方式
4. 各种数据的使用次序


在设计每种数据的二进制位组成时,需要考虑如何避免混包现象:

1. 粘包现象
2. 拆包现象


通信数据的两种基本组成方案:

1. 文本形式-----即将数据组合成特定形式的字符串,并规定字符串中不同子串的作用
        例如:“人名-年龄-工资”
2. 非文本形式----或称为二进制形式,即按字节或位指定数据中不同部分的作用
        例如:20字节存放人名+4字节存放年龄+4字节存放工资
3. 由多个文本加非文本组合而成的混合形式-----即交互数据中某些部分组合成字符串,另一些部分以二进制形式存在


交互数据按数据长度是固定还是不固定,组成方案分为如下两种:
1. 定长:所有数据长度固定为多少字节
2. 变长:有的数据长度比较短,有的数据长度比较长


通信数据组成方案两种分类相互交叉就可能存在如下几种情况:
1. 定长文本:
        发送方每次发送:1> 按数据格式在连续内存空间中组织好待发送的数据   2> 发送
        接收方每次接收:1> 分配好用于存放接收数据的内存空间   2> 接收
2. 变长文本
一般采用两种方式来避免混包:
        1> 以某个特殊字符或连续几个特殊字符的组合作为通信数据的结尾,例如:'\0'、'\n'、"\r\n"
        2> 在字符串内容上做文章。 例如:“0023abcxxx???” 其中0023表示后续有效字符的长度
发送方每次发送:1> 按数据格式在连续内存空间中组织好待发送的数据   2> 发送
接收方每次接收:

方案1过程:
        1)借助于一个临时文件,每次接收一个字节存放到临时文件,当接收到结尾标记时结束本轮接收
        2)计算临时文件大小
        3)动态分配空间
        4)从临时文件中将数据读入动态空间里

方案2过程:
        1) 接收固定长度的字节数
        2) sscanf 将其扫描成整数得到后续需要动态分配空间的大小:整数 + 第1步的固定长度
        3)动态分配空间
        4)strcpy 第1步读到内容到动态空间
        5)按第2步得到的整数去读后续数据

        由于是文本形式,因此与协议数据相关的代码大部分都会涉及字符串处理

3. 定长非文本
发送方每次发送:1> 按数据格式在连续内存空间中组织好待发送的数据   2> 发送
接收方每次接收:1> 分配好用于存放接收数据的内存空间   2> 接收
4. 变长非文本
5. 定长混合
        发送方每次发送:1> 按数据格式在连续内存空间中组织好待发送的数据   2> 发送
        接收方每次接收:1> 分配好用于存放接收数据的内存空间   2> 接收
6. 变长混合

        无论采用哪种都要考虑:1> 如何区分不同通信数据   2> 如何避免混包现象
        对于变长非文本和变长混合多数项目采用变长结构体来组织协议数据

对于通信数据是变长非文本或变长混合形式的通信程序,开发过程:
1. 按协议数据格式设计变长结构体--按协议格式组合而成的一个完整数据包在行业里统称为PDU(Protocol Data Unit协议数据单元)
2. 为通信各方编写各种数据的创建函数 和 统一的销毁函数 以及发送、接收函数 ------ 统称为协议代码
3. 任何想要发送数据的任务每次发送:
        1> 调用某一个创建函数,在连续的空间中按协议组织好待发送的数据
        2> 调用发送函数
        3> 调用销毁函数
4. 任何想要接收数据的任务每次接收:
        1> 调用接收函数
        2> 对接收下来的协议数据进行处理
        3> 调用销毁函数

实际项目开发中,涉及通信的软件开发,往往需要程序员:
1. 研究别人提供的通信协议
2. 自行设计新的通信协议

二者必选其一
服务端进程:或称服务器进程,为其它进程提供通信服务
客户端进程:使用通信服务的进程

示例:编写如下程序:
    客户端进程:接收用户输入的一个整数n,程序产生n个随机数,让用户选择对这n个随机数排序还是求均值,然后将对n个随机数的操作和n个随机数发送给服务端,接收服务端处理结果,并显示处理结果
    服务端进程:接收客户端的操作请求和n个随机数,然后完成相应的操作,将操作结果发送回给客户端

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

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

相关文章

与ai一起作诗(《校园清廉韵》)

与ai对话犹如拷问自己的灵魂&#xff0c;与其说ai助力还不如说在和自己对话。 (笔记模板由python脚本于2024年10月19日 19:18:33创建&#xff0c;本篇笔记适合喜欢python和诗歌的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&…

免费开源Odoo软件如何实现电商仓库高效发货

世界排名第一的免费开源ERP软件Odoo&#xff0c;拥有非常强大的仓库管理WMS功能。本文以电商仓库发货管理为例&#xff0c;介绍电商订单的仓库发货作业的各种方法。电商订单仓库发货流程&#xff0c;通常分为三个步骤&#xff0c;即拣货、打包、发货。根据仓库日处理订单数量的…

【密码分析学 笔记】 3.3 飞去来器攻击及矩形攻击

3.3 飞去来器攻击及矩形攻击 飞去来器攻击&#xff1a; 轮数短但概率高的差分路线需要选择明文和密文 增强飞去来器攻击&#xff1a; 通过加大选择明文量来去掉选择密文的要求只选择明文 矩形攻击&#xff1a; 同时利用多条短轮路线提升区分器概率降低攻击复杂度 后续研…

【面试题】什么是SpringBoot以及SpringBoot的优缺点

什么是SpringBoot以及SpringBoot的优缺点 什么是SpringBoot SpringBoot是基于Spring的一个微框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。 SpringBoot的优点 可以创建独立的Spring应用程序&#xff0c;并且基于其Maven或Gradle插件&#xff0c;可以创建可执…

SpringCloudAlibaba-Nacos

概述和版本说明 <spring.boot.version>3.2.0</spring.boot.version> <spring.cloud.version>2023.0.0</spring.cloud.version> <spring.cloud.alibaba.version>2022.0.0.0</spring.cloud.alibaba.version>注册中心&#xff0c;配置中心及…

Docker 安装Postgres和PostGIS,并制作镜像

1. 查找postgres和postgis现有的镜像和版本号 镜像搜索网站&#xff1a;https://docker.aityp.com/ 测试使用的是postgres:15.4 和 postgis:15-3.4 2、镜像拉取 docker pull postgres:15.4docker pull postgis/postgis:15-3.4镜像下载完成&#xff0c;docker images 查看如…

【C++】拆分详解 - 模板

文章目录 一、泛型编程二、函数模板1. 概念2. 语法3. 函数模板的原理4. 函数模板的实例化5. 模板参数的匹配原则 三、类模板1. 语法2. 实例化 四、模板的特化1. 概念2. 函数模板特化3. 类模板特化3.1 全特化3.2 偏特化 / 半特化3.3 应用示例 4. 小结 五、模板的分离编译1. 分离…

秋招面试题记录_半结构化面试

c八股(可能问的多一点) 1.简单说说C11语法特性 答&#xff1a; 1.auto以及decltype自动类型推导&#xff0c;避免手动声明复杂类型&#xff0c;减少冗长代码提升了可读性和安全性。 2.智能指针 自动释放内存 (具体说说) 有shared和unique 差异主要体现在所有权、内存开销、…

微积分复习笔记 Calculus Volume 1 - 3.4 Derivatives as Rates of Change

3.4 Derivatives as Rates of Change - Calculus Volume 1 | OpenStax

京东 北京 java 中级: 哪些情况下的对象会被垃圾回收机制处理掉? 哪些对象可以被看做是 GC Roots 呢?对象不可达,一定会被垃圾收集器回收么?

我同学最近在面试java的岗位, 这是他遇到的某些关于java的JVM中垃圾回收相关的部分的问题, 他来问我, 我特以此文章来解答. 公司 京东 base 北京 面试时间 2024年10月23日16:00:00 他跟我说, 面试官一上来就问了一个关于JVM的问题, 直接就给他难住了, 问题是 : 哪些情况下…

数据结构《顺序表》

文章目录 前言一、什么是顺序表&#xff1f;1.1 顺序表的概念1.2 顺序表的建立 二、MyArrayList的实现三、顺序表的方法四、关于顺序表的例子总结 前言 提示&#xff1a;这里涉及到的ArrayList类是一个泛型类&#xff0c;同时后面的很多内容都会涉及到泛型&#xff0c;如果不了…

【蓝队技能】【内网隧道工具流量分析】FRPNPSreGeorgVenom

蓝队技能 FRP&NPS&reGeorg&Venom 蓝队技能总结前言一、FRP1.1 流量分析1.2 特征提取 二 NPS1.1 流量分析1.2 特征提取 三、reGeor1.1 特征提取 四、Venom1.1 特征提取 总结 前言 本文聚焦内网隧道代理技术&#xff0c;涵盖Frp、Nps、Neo-reGeorg及Venom等工具。这些…

潜水定位通信系统的功能和使用方法_鼎跃安全

潜水定位通信系统是保障潜水安全与作业高效的关键设备。它利用先进的声呐、无线电等技术&#xff0c;可精准定位潜水员位置。在水下能实现潜水员之间以及与水面的双向通信&#xff0c;确保信息及时传递。具备高可靠性和稳定性&#xff0c;即使在复杂水环境中也能正常运行。 一、…

Git Push(TODO)

最近经常碰到GIT push不上去的问题。到处求人解决也真是尴尬&#xff0c;想自己看看&#xff0c;所以刚刚在github上建了一个仓&#xff0c;试了下。结果如下&#xff1a; 暂时可能还不行&#xff0c;因为数据都是加密的&#xff0c;没法看到具体GIT的交互信息。。。 后面再想办…

算法的学习笔记—两个链表的第一个公共结点(牛客JZ52)

&#x1f600;前言 在链表问题中&#xff0c;寻找两个链表的第一个公共结点是一个经典问题。这个问题的本质是在两个单链表中找到它们的相交点&#xff0c;或者说它们开始共享相同节点的地方。本文将详细讲解这个问题的解题思路&#xff0c;并提供一种高效的解决方法。 &#x…

WPFDeveloper正式版发布

WPFDeveloper WPFDeveloper一个基于WPF自定义高级控件的WPF开发人员UI库&#xff0c;它提供了众多的自定义控件。 该项目的创建者和主要维护者是现役微软MVP 闫驚鏵: https://github.com/yanjinhuagood 该项目还有众多的维护者&#xff0c;详情可以访问github上的README&…

Golang | Leetcode Golang题解之第497题非重叠矩形中的随机点

题目&#xff1a; 题解&#xff1a; type Solution struct {rects [][]intsum []int }func Constructor(rects [][]int) Solution {sum : make([]int, len(rects)1)for i, r : range rects {a, b, x, y : r[0], r[1], r[2], r[3]sum[i1] sum[i] (x-a1)*(y-b1)}return Sol…

SpringBoot项目ES6.8升级ES7.4.0

SpringBoot项目ES6.8.15 升级到 ES7.4.0 前言 由于公司内部资产统一整理&#xff0c;并且公司内部部署有多个版本的es集群&#xff0c;所以有必要将目前负责项目的ES集群升级到公司同一版本7.4.0。es6到es7的升级变化还是挺大的&#xff0c;因此在这里做一下简单记录&#xf…

从新手到高手:map和set的使用技巧全攻略(C++)

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C&#xff1a;由浅入深篇 小新的主页&#xff1a;编程版小新-CSDN博客 前言&#xff1a; 本章节讲解的map和set底层…

C++新基础类型(C++11~C++20)

本文章记录C11~C20的新基础类型。 1.整数类型long long long long类型是C11引入的。在C标准中规定&#xff0c;long long是一个至少为64位的整数类型。可以使用LL和ULL字面量后缀进行初始化。格式化打印时分别用%lld和%llu。 long long x 12345LL; unsigned long long y 4…