Linux进程通信:无名管道

news2024/12/23 23:26:08

进程通信目的:

(1)数据传输:进程间数据传输;

(2)通知事件:一个进程向另一个或一组进程发送消息,通知某个事件的发生(如子进程终止时需通知父进程);

(3)资源共享:多个进程共享资源,需要内核提供同步互斥机制;

(4)进程控制:某进程需要控制另一个进程的执行(如Debug进程),此时控制进程需要拦截另一个进程的所有陷入、异常、状态等。

进行通信分类及方式:


1. 无名管道

特点:(1)半双工。数据同一时刻只能单向传输;

           (2)数据从管道一端写入,另一端读出;

           (3)写入管道的数据遵循先进先出;

           (4)管道非普通文件,不属于某个文件系统,只存在于内存;

           (5)无名管道只能在具有公共祖先的进程(父子进程、兄弟进程等)之间使用

(1)pipe函数:创建无名管道

#include<unistd.h>

int pipe(int pipefd[2]);
/*
功能:
    创建无名管道。
参数:
    pipefd:int型数组的首地址,存放了管道文件描述符pipefd[0]、pipefd[1]。
            pipefd[0]用于读管道,pipefd[1]用于写管道。
            一般的文件I/O函数都可用来操作管道(lseek除外)。
返回值:
    成功:0
    失败:-1
*/

pipe示例:

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

int test() {
    int fds[2];  // fds[0]用于读管道,fds[1]用于写管道
    int ret = -1;

    // 创建一个无名管道
    ret = pipe(fds);
    if (-1 == ret) {
        perror("pipe");
        return 1;
    }

    printf("读管道的文件描述符:%d, 写管道的文件描述符:%d\n", fds[0], fds[1]);

    // 关闭文件描述符
    close(fds[0]);
    close(fds[1]);
    return 0;
}

运行结果:

(2)父子进程使用无名管道通信原理:

a)需要在fork之前创建无名管道,然后子进程也有自己的读写管道描述符关联无名管道;

b)父进程给子进程发消息:父进程写管道、子进程读管道;需要关闭父进程的读端文件描述符(fds[0])、子进程的写端文件描述符(fds[1])。 反之类似。

c)管道默认为阻塞,读不到内容则阻塞等待有内容可读;可设置为非阻塞。

(3)管道读写特性:

case 1:

        a)若写端打开,管道中无数据,读端进程会阻塞;

        b)若写端打开,管道中有数据,读端进程将数据读出,下次若无数据可读则阻塞;

case 2:

        若写端关闭,读端进程读取全部内容后,返回0;

case 3:

        若读端打开,管道被写满,则写端进程阻塞;

case 4:

        若读端关闭,写端进程收到一个信号,然后退出。

查看管道大小:

(4)父子进程使用无名管道通信示例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>

#define SIZE 64

int main(int argc, const char* argv[]) {

    int ret = -1;
    int fds[2];
    pid_t pid = -1;
    char buf[SIZE];

    // 1. 创建无名管道
    ret = pipe(fds);
    if (-1 == ret) {
        perror("pipe");
        return 1;
    }

    // 2. 创建子进程。需要在创建无名管道之后
    pid = fork();
    if (-1 == pid) {
        perror("fork");
        return 1;
    }

    // 子进程 读管道
    if (0 == pid) {
        close(fds[1]);  // 关闭写端

        ret = read(fds[0], buf, SIZE); // 读管道
        if (ret < 0) {
            perror("read");
            exit(-1);
        }

        printf("子进程读到的内容:%s\n", buf);

        close(fds[0]);  // 关闭读端
        exit(0); // 子进程退出
    }

    // 父进程 写管道
    close(fds[0]); // 关闭读端

    ret = write(fds[1], "ABCDEFG", 7);  // 写管道
    if (-1 == ret) {
        perror("write");
        return 1;
    }
    printf("父进程写了%d字节.\n", ret);
    close(fds[1]);  // 关闭写端

    return 0;
}

运行结果:

(5)fpathconf函数:查看管道缓冲区

#include<unistd.h>

long fpathconf(int fd, int name);
/*
功能:
    通过name查看管道缓冲区的不同属性
参数:
    fd:读端或写端文件描述符
    name:
        _PC_PIPE_BUF:查看管道缓冲区大小
        _PC_NAME_MAX:文件名字节数上限
返回值:
    成功:属性值
    失败:-1
*/

fpathconf示例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>

int main(int argc, const char* argv[]) {

    int fds[2];
    int ret = -1;

    ret = pipe(fds);
    if (-1 == ret) {
        perror("pipe");
        return 1;
    }

    printf("读端缓冲区大小:%ld,\n写端缓冲区大小:%ld,\n读端文件名字节数上限:%ld,\n写端文件名字节数上限:%ld\n",
        fpathconf(fds[0], _PC_PIPE_BUF), fpathconf(fds[1], _PC_PIPE_BUF),
        fpathconf(fds[0], _PC_NAME_MAX), fpathconf(fds[1], _PC_NAME_MAX));

    return 0;
}

运行结果:

(6)管道读端缓冲区设置为非阻塞的方法:

// 获取读端缓冲区原先的状态标记flags 
int flags = fcntl(fd[0], F_GETFL); 

// 设置新状态标记flags加入非阻塞状态
flags |= O_NONBLOCK;

// 给读端缓冲区设置新状态标记
fcntl(fd[0], F_SETFL, flags);

读端设置为非阻塞,若无数据,读进程直接返回-1.

读端以非阻塞的方式读管道示例:

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

#define SIZE 64

int main(int argc, const char* argv[]) {

    int ret = -1;
    int fds[2];
    pid_t pid = -1;
    char buf[SIZE];

    // 1. 创建无名管道
    ret = pipe(fds);
    if (-1 == ret) {
        perror("pipe");
        return 1;
    }

    // 2. 创建子进程。需要在创建无名管道之后
    pid = fork();
    if (-1 == pid) {
        perror("fork");
        return 1;
    }

    // 子进程 读管道
    if (0 == pid) {
        close(fds[1]);  // 关闭写端

        /*设置读端非阻塞*/
        ret = fcntl(fds[0], F_GETFL);  // 获取读端缓冲区状态
        ret |= O_NONBLOCK; //将读端缓冲区加入非阻塞状态
        fcntl(fds[0], F_SETFL, ret); // 将新状态设置进入

        ret = read(fds[0], buf, SIZE); // 读管道
        if (ret < 0) {
            perror("read");
            exit(-1);
        }

        printf("子进程读到的内容:%s\n", buf);

        close(fds[0]);  // 关闭读端
        exit(0); // 子进程退出
    }

    // 父进程 写管道
    sleep(1);
    close(fds[0]); // 关闭读端

    ret = write(fds[1], "ABCDEFG", 7);  // 写管道
    if (-1 == ret) {
        perror("write");
        return 1;
    }
    printf("父进程写了%d字节.\n", ret);
    close(fds[1]);  // 关闭写端

    return 0;
}

运行结果:

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

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

相关文章

使用Lim测试平台快速完成批量造数

一、前言 在我们平时的测试过程中&#xff0c;经常遇到需要造大量数据的情况&#xff0c;比如&#xff1a;测试分页功能&#xff0c;性能压测、数据准备等。 这时我们可以通过写脚本或jmeter这类的工具来实现&#xff0c;但这些方式在团队协作的时候并不友好&#xff0c;当别人…

MySQL 函数和运算符

文章目录 一、MySQL 函数二、MySQL 运算符总结 一、MySQL 函数 MySQL 有很多内置的函数&#xff0c;以下列出了这些函数的说明。 二、MySQL 运算符 算术运算符 比较运算符 逻辑运算符 位运算符算术运算符 MySQL 支持的算术运算符包括: 除法运算和模运算中&#xf…

(2)elasticsearch环境搭建(win10)

安装jdk 版本选择&#xff1a;最好是java 8、java11或者java14 jdk兼容性&#xff1a;https://www.elastic.co/cn/support/matrix#matrix_jvm 操作系统兼容性&#xff1a;https://www.elastic.co/cn/support/matrix 自身兼容性&#xff1a;https://www.elastic.co/cn/suppo…

Linux下版本控制器(SVN) -服务器端环境搭建步骤

文章目录 进阶知识-Linux下版本控制器(SVN)4、服务器端环境搭建步骤4.1 安装服务器端程序4.2 验证是否安装成功4.3 创建并配置版本库4.4 配置 SVN对应的服务4.5 启动 SVN服务 本人其他相关文章链接 进阶知识-Linux下版本控制器(SVN) 4、服务器端环境搭建步骤 4.1 安装服务器端…

AD7356_SPI驱动程序设计_5MSPS_Verilog

好久没动手了&#xff0c;使用Verilog编写一个AD7356的SPI驱动程序。 AD7356是一个双通道、12位、低功耗的ADC。最高采样速率可达5MSPS&#xff0c;全功率输入带宽为110MHz。AD7356的引脚图如下。 SPI的时序图如下&#xff0c;为了使单通道的采样速率达到最高的5MSPS&#xff…

mac m1的docker nacos2.0.3访问宿主机器的mysql

一、环境介绍&#xff1a; 我的mac系统&#xff1a;m1芯片 macOs Ventura 13.1 我的docker版本&#xff1a;v20.10.8 本机msyql&#xff1a;8.0.25 端口&#xff1a;3306。 mysql版本查询脚本&#xff1a;select version() from dual; 二、准备安装nacos2.0.3 m1版本的镜像 …

Vue+Echarts 项目演练(中)后台数据接口的创建

全局引用Echarts与axios 后台接口创建express路由 api接口数据创建 全局引用Echarts与axios vue3.0的挂载方式&#xff1a;使用Provide/Inject依赖注入&#xff0c;将替代vue2中在原型链上挂载一些属性在app.vue中使用provider来给后代们提供数据 <script> import { p…

组态王与FX3U之间无线通讯(485BD口)

设备与设备之间互相通信&#xff0c;需要一座桥梁把二者连接起来&#xff0c;那就是传输通路与通信协议。 传输通路由传输介质与传输接口组成&#xff0c;传输介质可分为有线和无线传输介质两大类。传输接口即通信模块。传输接口常见的有三种RS-232、RS-485和RS-422通信模块。…

干货|英国专利申请

英国是世界上公认的一个实施现代专利制度的国家。英国1624年颁布的《垄断法案》被认为是世界上一部具有现代意义的专利法&#xff0c;并成为现代专利保护制度系的起点。英国现行的专利法于1977年颁布&#xff0c;并于1978年生效。英国的专利制度在保护发明创造&#xff0c;促进…

21.Java网络通信

目录 1. Java基本介绍 2. JDK下载安装及其环境配置 3. 一个简单的java程序 4. Eclipse基本使用、数据类型、运算符 5. 控制语句&#xff08;if、switch、for、while、foreach&#xff09; 6. Java数组 7. Java字符串对象(String|StringBuffer|StringBuilder|StringJoiner…

Asp.NET CORE实验室信息管理系统源码,支持LIS独立部署,Docker部署

技术架构&#xff1a;Asp.NET CORE 3.1 MVC SQLserver Redis等 基于B/S架构的实验室管理系统源码&#xff0c;整个系统的运行基于WEB层面&#xff0c;只需要在对应的工作台安装一个浏览器软件有外网即可访问。全套系统采用云部署模式&#xff0c;部署一套可支持多家医院检验科…

Java ---Object根类

(一&#xff09;定义 官方说法&#xff1a; 在Java中&#xff0c; Object 类是所有类的父类&#xff0c;即Java 的所有类都继承了 Object&#xff0c;子类可以使用 Object 的所有方法。 注意&#xff1a; Object类型的变量与除Object以外的任意引用数据类型的对象都多态引用 所…

youdiancms 9.5.0 版本 SQL注入(vulfocus复现)

启动服务 从上述信息&#xff0c;可以看到&#xff0c;web服务的80端口被映射到62461端口&#xff0c;并且该服务对外开启了3306端口并映射到20130 端口。并且给了数据库的相关信息。 配置web数据库 登陆后台&#xff0c;后台如下&#xff1a; 探测注入点 上述提到注入点是M…

OpenGL教程之 纹理练习

网址 LearnOpenGL 练习一 修改片段着色器&#xff0c;仅让笑脸图案朝另一个方向看。  解析&#xff1a;朝向另一个方向很简单&#xff0c;即让上文中的图片进行左右对称变换即可&#xff0c;即将片段着色器中笑脸的纹理坐标从textCord转换为vec2( 1 - textCord.x, text.y …

【淘宝】商品列表页数据采集+商品销量数据采集代码

采集场景 在淘宝首页&#xff08;https://s.taobao.com/&#xff09;输入关键词搜索&#xff0c;采集搜索后得到的商品列表页数据。示例中关键词为【耐克】&#xff0c;可根据需求进行更换&#xff0c;同时支持自动批量输入多个关键词。 采集字段 采集字段包括关键字文本值…

Nginx和tomcat反向代理(动静分离)

正向代理&#xff1a; 当用户想访问某一网址时&#xff0c;用户先访问代理服务器&#xff0c;然后由代理服务器向目标网址发送请求最终将数据返回代理服务器&#xff0c;最后代理服务器将数据返回给用户这一过程我们称之为正向代理。 反向代理&#xff1a;基本流程是与正向代理…

【react全家桶学习】如何创建一个react组件(超详)

前提是你安装了react脚手架&#xff0c;不会的看这里&#xff0c;然后再进行创建哦~ 【react全家桶学习】初始化react脚手架及项目结构讲解_suohs Blog的博客-CSDN博客 目录 问题1&#xff1a;如何创建一个简单的hello组件&#xff1f; 问题2&#xff0c;如果组件特别多怎么…

庚顿数据正式发布军工版实时数据库庚金3.0,鼎力支撑中国国防数字化

庚金实时数据库管理系统是北京庚顿数据科技有限公司旗下自主知识产权的军工级产品&#xff0c;可有效满足特种行业自主产权、高性能、高安全、高稳定等高端需求&#xff0c;轻松实现海量实时数据高频采集、海量存储等应用场景&#xff0c;切实保障了客户生产活动的稳定运行。庚…

c/c++:数组做函数参数,传入函数的首地址,相当于传址,指针做函数返回值,数组止做c语言中函数的返回值

c/c:数组做函数参数&#xff0c;传入函数的首地址&#xff0c;相当于传址&#xff0c;指针做函数返回值&#xff0c;数组禁止做c语言中函数的返回值 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0…

Python小姿势 - Python基础知识

Python基础知识 Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。 Python的创始人为吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;&#xff0c;于1989年底发布第一个公开发行版本——0.9.0。 自2004年以来&#xff0c;Python已经成为顶级开源项目&…