Linux-----进程通讯(管道Pipe)

 目录

 进程不共享内存

匿名管道

 通过匿名管道实现通讯

有名管道

库函数mkfifo()

案例 


 进程不共享内存

 不同进程之间内存是不共享的。是相互独立的。

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

int num = 0;

int main(int argc, char const *argv[])
{
    __pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        num = 100;
        printf("子进程中,num的值:%d\n", num);
    }
    else {
        sleep(1);
        printf("父进程中,num的值:%d\n", num);
    }
}

匿名管道

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

int main(int argc, char const *argv[])
{
    fopen("/opt","a+");
    printf("出问题%d\n", errno);
    perror("fopen");
    return 0;
}

当系统调用或库函数发生错误时,通常会通过设置全局变量errno来指示错误的具体原因。errno是在C语言(及其在Unix、Linux系统下的应用)中用来存储错误号的一个全局变量。每当系统调用或某些库函数遇到错误,无法正常完成操作时,它会将一个错误代码存储到errno中。这个错误代码提供了失败的具体原因,程序可以通过检查errno的值来确定发生了什么错误,并据此进行相应的错误处理。

errno定义在头文件<errno.h>中,引入该文件即可调用全局变量errno。

perror函数用于将errno当前值对应的错误描述以人类可读的形式输出到标准错误输出(stderr)。

参数s:指向一个字符串的指针,如果s不是空指针且指向的不是\0字符,则perror会在s后添加一个冒号和空格作为前缀,输出错误信息,否则不输出前缀,直接输出错误信息。

 通过匿名管道实现通讯

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

// 管道实现进程间通讯
int main(int argc, char const *argv[])
{
    // 将程序传进来的第一个命令行参数,通过管道传输给子进程
    int pipefd[2];
    __pid_t cpid;
    if (pipe(pipefd) == -1) {
        perror("创建管道失败");
        exit(EXIT_FAILURE);
    }

    if (argc != 2) {
        printf("参数太少了\n");
        exit(EXIT_FAILURE);
    }
    cpid = fork();
    if (cpid == -1) {
        perror("创建进程失败");
        exit(EXIT_FAILURE);
    }

    if (cpid == 0) {
        // 子进程,读取数据
        close(pipefd[1]); // 关闭写端
        // printf("子进程读取的数据:\n");
        char* str = "子进程读取的数据:";
        write(STDOUT_FILENO, str, strlen(str));
        char buf;
        while (read(pipefd[0], &buf, 1) > 0) {
            write(STDOUT_FILENO, &buf, 1);
        }
        write(STDOUT_FILENO, "\n", 1);
        close(pipefd[0]); // 关闭读端
        exit(EXIT_SUCCESS);
    }
    else {
        // 父进程,写入数据
        close(pipefd[0]); // 关闭读端
        printf("进程%d写入数据:%s\n", getpid(),argv[1]);
        write(pipefd[1], argv[1], strlen(argv[1]));
        close(pipefd[1]); // 关闭写端
        waitpid(cpid, NULL, 0);
        exit(EXIT_SUCCESS);
    }
    return 0;
}


有名管道

上文介绍的Pipe是匿名管道,只能在有父子关系的进程间使用,某些场景下并不能满足需求。与匿名管道相对的是有名管道,在Linux中称为FIFO,即First In First Out,先进先出队列。

FIFO和Pipe一样,提供了双向进程间通信渠道。但要注意的是,无论是有名管道还是匿名管道,同一条管道只应用于单向通信,否则可能出现通信混乱(进程读到自己发的数据)。

有名管道可以用于任何进程之间的通信。

库函数mkfifo()

执行man 3 mkfifo查看文件说明。

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

/**
 * @brief 用于创建有名管道。该函数可以创建一个路径为pathname的FIFO专用文件,mode指定了FIFO的权限,FIFO的权限和它绑定的文件是一致的。FIFO和pipe唯一的区别在于创建方式的差异。一旦创建了FIFO专用文件,任何进程都可以像操作文件一样打开FIFO,执行读写操作。
 * 
 * @param pathname 有名管道绑定的文件路径
 * @param mode 有名管道绑定文件的权限
 * @return int 
 */
int mkfifo(const char *pathname, mode_t mode);

案例 

发送端:

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

int main(int argc, char const *argv[])
{
    // 每次用完最好要释放掉
    char* pipe_path = "/tmp/mtfifo";
    int fifo = mkfifo(pipe_path, 0666);
    if (fifo == -1) {
        perror("mkfifo");
        if (errno != 17) {
            exit(EXIT_FAILURE);
        }
    }
    //  对有名管道创建一个文件描述符fd
    int fd = open(pipe_path, O_WRONLY); //只能写

    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    char buf[100];
    ssize_t readnum;
    //  读取到控制台的数据写入管道中
    while ((readnum = read(STDIN_FILENO, buf, sizeof(buf))) > 0)
    {
        write(fd, buf, readnum);
    }
    if (readnum < 0) {
        perror("read");
        close(fd);
        exit(EXIT_FAILURE);
    }
    printf("写入完成\n");
    close(fd);
    // 释放管道
    if (unlink(pipe_path) == -1) {
        perror("unlink");
    }

    return 0;
}

接收端:

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

int main(int argc, char const *argv[])
{
    char* pipe_path = "/tmp/mtfifo";
    // if (unlink(pipe_path) == -1) {
    //     perror("unlink");
    //     // 如果删除失败,可能是因为管道不存在,所以忽略错误
    // }
    int fifo = mkfifo(pipe_path, 0666);
    if (fifo == -1) {
        perror("mkfifo");
        if (errno != 17) {
            exit(EXIT_FAILURE);
        }
    }
    //  对有名管道创建一个文件描述符fd
    int fd = open(pipe_path, O_RDONLY); //只能读

    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    char buf[100];
    ssize_t readnum;
    //  读取管道信息,放到控制台
    while ((readnum=read(fd,buf,sizeof(buf))) > 0)
    {
        write(STDIN_FILENO, buf, readnum);
    }
    


    if (readnum < 0) {
        perror("read");
        close(fd);
        exit(EXIT_FAILURE);
    }
    printf("读端接收管道数据完成\n");
    
    close(fd);
    return 0;
}

注意

调用open()打开有名管道时,flags设置为O_WRONLY则当前进程用于向有名管道写入数据,设置为O_RDONLY则当前进程用于从有名管道读取数据。设置为O_RDWR从技术上是可行的,但正如上文提到的,此时管道既读又写很可能导致一个进程读取到自己发送的数据,通信出现混乱。因此,打开有名管道时,flags只应为O_WRONLY或O_RDONLY。

内核为每个被进程打开的FIFO专用文件维护一个管道对象。当进程通过FIFO交换数据时,内核会在内部传递所有数据,不会将其写入文件系统。因此,/tmp/myfifo文件大小始终为0。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[工具]git克隆远程仓库到本地快速操作流程

一、新建空目录 二、初始化本地仓库 git init 初始化成功后&#xff0c;会在当前目录生成一个.git的目录。 三、关联远程仓库 git remote add origin <URL>这一步让本地仓库与远程仓库进行关联&#xff0c;origin是远程仓库的别名&#xff0c;可以自定义。 四、克隆…

机器学习之贝叶斯分类器和混淆矩阵可视化

贝叶斯分类器 目录 贝叶斯分类器1 贝叶斯分类器1.1 概念1.2算法理解1.3 算法导入1.4 函数 2 混淆矩阵可视化2.1 概念2.2 理解2.3 函数导入2.4 函数及参数2.5 绘制函数 3 实际预测3.1 数据及理解3.2 代码测试 1 贝叶斯分类器 1.1 概念 贝叶斯分类器是基于贝叶斯定理构建的分类…

基于phpstudy快速搭建本地php环境(Windows)

好好生活&#xff0c;别睡太晚&#xff0c;别爱太满&#xff0c;别想太多。 2025.1.07 声明 仅作为个人学习使用&#xff0c;仅供参考 对于CTF-Web手而言&#xff0c;本地PHP环境必不可少&#xff0c;但对于新手来说从下载PHP安装包到配置PHP环境是个非常繁琐的事情&#xff0…

张朝阳惊现CES展,为中国品牌 “代言”的同时,或将布局搜狐新战略!

每年年初&#xff0c;科技圈的目光都会聚焦在美国拉斯维加斯&#xff0c;因为这里将上演一场被誉为 “科技春晚” 的年度大戏 ——CES 国际消费电子展。作为全球规模最大、最具影响力的科技展会之一&#xff0c;CES 吸引了来自 160 多个国家的创新者和行业领导者&#xff0c;是…

Ollama VS LocalAI:本地大语言模型的深度对比与选择指南

随着人工智能技术的快速发展&#xff0c;大语言模型逐渐成为多个行业的重要工具。从生成内容到智能问答&#xff0c;大模型展现了强大的应用潜力。然而&#xff0c;云端模型的隐私性、使用成本和网络依赖等问题也促使更多用户关注本地化解决方案。Ollama 和 LocalAI 是近年来备…

【C++】B2101 计算矩阵边缘元素之和

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目背景与描述题目描述输入格式输出格式输入输出样例说明与提示 &#x1f4af;分析与解决方案解法一&#xff1a;我的做法代码实现解题思路优点与局限性 解法二&#xff1…

保护性暂停原理

什么是保护性暂停&#xff1f; 保护性暂停&#xff08;Guarded Suspension&#xff09;是一种常见的线程同步设计模式&#xff0c;常用于解决 生产者-消费者问题 或其他需要等待条件满足后再继续执行的场景。通过这种模式&#xff0c;一个线程在执行过程中会检查某个条件是否满…

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>字母大小写全排列

题目&#xff1a; 解析&#xff1a; 代码&#xff1a; private List<String> ret;private StringBuffer path;public List<String> letterCasePermutation(String s) {ret new ArrayList<>();path new StringBuffer();dfs(s,0);return ret;}private voi…

解决nginx多层代理后应用部署后访问发现css、js、图片等样式加载失败

一般是采用前后端分离部署方式&#xff0c;被上一层ng代理后&#xff0c;通过域名访问报错&#xff0c;例如&#xff1a;sqx.com.cn/应用代理路径。 修改nginx配置&#xff0c;配置前端页面的路径&#xff1a; location / {proxy_pass http://前端页面所在服务器的IP:PORT;pro…

前端-计算机网络篇

一.网络分类 1.按照网络的作用范围进行分类 &#xff08;1&#xff09;广域网WAN(Wide Area Network) 广域网的作用范围通常为几十到几千公里,因而有时也称为远程网&#xff08;long haul network&#xff09;。广域网是互联网的核心部分&#xff0c;其任务是长距离运送主机…

挑战20天刷完leecode100

2025.1.5 二分查找 1 搜索插入位置 就是简单的二分查找 注意开闭就行 这里有一句话就是nums是升序的 如果他不是严格递增 就是有相同的数字的情况下应该怎么写? int lower_bound(vector<int>& nums, int target) {int left 0, right (int) nums.size() - 1; …

Android原生开发同一局域网内利用socket通信进行数据传输

1、数据接收端代码如下&#xff0c;注意&#xff1a;socket 接收信息需要异步运行&#xff1a; // port 端口号自定义一个值&#xff0c;比如 8888&#xff0c;但需和发送端使用的端口号保持一致 ServerSocket serverSocket new ServerSocket(port); while (true) {//这里为了…

Linux 获取文本部分内容

Linux获取文本部分内容 前言场景获取前几行内容获取末尾几行内容获取中间内容head 命令 tail 命令 结合sed 命令awk 命令 前言 test.log 文本内容如下&#xff1a; &#xff08;注意&#xff1a;内容 a1004和a1005之间有一空行&#xff09; [rootgaussdb002 tmp]# cat test.…

常见的端口号大全,2025年整理

端口号是网络通信的基础&#xff0c;它定义了不同服务的入口和出口。了解服务端口号不仅有助于网络配置&#xff0c;还能提升问题排查效率。在实际应用中&#xff0c;熟悉常见端口号可以帮助你快速定位网络故障、优化服务性能&#xff0c;并确保网络安全。 一、常见的网络服务…

音视频入门基础:MPEG2-PS专题(6)——FFmpeg源码中,获取PS流的视频信息的实现

音视频入门基础&#xff1a;MPEG2-PS专题系列文章&#xff1a; 音视频入门基础&#xff1a;MPEG2-PS专题&#xff08;1&#xff09;——MPEG2-PS官方文档下载 音视频入门基础&#xff1a;MPEG2-PS专题&#xff08;2&#xff09;——使用FFmpeg命令生成ps文件 音视频入门基础…

【Arthas命令实践】heapdump实现原理

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 使用原理 使用 dump java heap, 类似 jmap 命令的 heap dump 功能。 【dump 到指定文件】 heapdump arthas-output/dump.hprof【只 …

【JavaEE】—— SpringBoot项目集成百度千帆AI大模型(对话Chat V2)

本篇文章在SpringBoot项目中集成百度千帆提供的大模型接口实现Chat问答效果&#xff1a; 一、百度智能云 百度千帆大模型平台是百度智能云推出的一个企业级一站式大模型与AI原生应用开发及服务平台。 注册地址&#xff1a;https://qianfan.cloud.baidu.com/ 注册成功后&…

【我的 PWN 学习手札】IO_FILE 之 FSOP

FSOP&#xff1a;File Stream Oriented Programming 通过劫持 _IO_list_all 指向伪造的 _IO_FILE_plus&#xff0c;进而调用fake IO_FILE 结构体对象中被伪造的vtable指向的恶意函数。 目录 前言 一、glibc-exit函数浅析 二、FSOP 三、Largebin attack FSOP &#xff08;…

语音技术与人工智能:智能语音交互的多场景应用探索

引言 近年来&#xff0c;智能语音技术取得了飞速发展&#xff0c;逐渐渗透到日常生活和各行各业中。从语音助手到智能家居控制&#xff0c;再到企业客服和教育辅导&#xff0c;语音交互正以前所未有的速度改变着人机沟通的方式。这一变革背后&#xff0c;人工智能技术无疑是关键…

三、Angular 路由

一、简介 Angular 的路由服务是一个可选的服务&#xff0c;它用来呈现指定的 URL 所对应的视图。它并不是Angular 核心库的一部分&#xff0c;而是位于 angular/router 包中。像其他 Angular 包一样&#xff0c;路由服务在用户需要时才从此包中导入。 [1]. 创建路由模块 默认…