Linux -- 进程间通信的五种方式

news2024/10/6 18:22:29

IPC(InterProcess Communication)的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中Socket和Stream支持不同主机上的两个进程IPC。

  1. 管道(Pipes):管道是一种半双工的通信方式,用于具有亲缘关系的进程间通信。它通常用于父子进程或者兄弟进程之间。管道可以是匿名管道,也可以是命名管道。

  2. 消息队列(Message Queues):消息队列是一种通过消息传递进行通信的方式。发送方将消息发送到队列中,接收方从队列中接收消息。消息队列可以实现进程间的异步通信。

  3. 信号量(Semaphores):信号量是一种计数器,用于控制对共享资源的访问。它通常用于同步进程之间的操作,以避免竞争条件。

  4. 共享内存(Shared Memory):共享内存是一种允许多个进程访问同一块内存区域的方式。这种方式通常比较高效,但需要处理进程间的同步和互斥。

  5. 套接字(Sockets):套接字是一种网络编程接口,不仅可以用于不同主机间的进程通信,也可以用于同一主机上的进程通信。套接字可以基于网络协议(如TCP/IP)或本地协议(如UNIX域套接字)实现。

一、管道

管道(Pipes)是一种在Unix和类Unix系统中常见的进程间通信(IPC)机制,用于在具有亲缘关系的进程之间传递数据。管道是一个单向通道,允许一个进程将输出直接发送到另一个进程的输入。它是一种半双工通信方式,即数据只能单向流动,不能双向传输。

类型

  1. 匿名管道(Anonymous Pipes):匿名管道是最简单的管道形式,它只存在于内存中,并且通常用于父子进程之间的通信。在Unix系统中,可以使用pipe()系统调用创建匿名管道。

  2. 命名管道(Named Pipes):命名管道是一种具有持久性的管道,它以文件的形式存在于文件系统中,并允许无关进程之间进行通信。命名管道通常用于不具有亲缘关系的进程之间的通信。

特点

  • 单向通信:管道是单向的,数据只能沿着管道的方向流动,不能双向传输。

  • 半双工:管道是半双工的,即数据只能在一个方向上传输。如果需要双向通信,通常需要创建两个管道。

  • FIFO(先进先出):管道遵循FIFO的原则,即数据按照写入的顺序从管道中读取出来。

使用

在Unix系统中,可以使用pipe()系统调用创建匿名管道,它返回两个文件描述符,一个用于读取,一个用于写入。然后可以使用fork()创建一个新的进程,在父子进程之间共享管道,并使用dup2()系统调用将管道文件描述符重定向到标准输入或标准输出。接着,一个进程可以通过写入管道的方式向另一个进程发送数据,另一个进程则可以通过读取管道来接收数据。

示例

下面是一个简单的C语言示例,演示了如何在父子进程之间使用匿名管道进行通信:

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

int main()
{
        int fd[2];

        int pid;

        char buf[128];

        //创建管道
        if(pipe(fd) == -1) { 
                printf("creat pipe failed\n");
        }

        //创建子进程
        pid = fork();

        if(pid < 0) {
                printf("creat child faild\n");
        } else if(pid > 0) {    //父进程
                printf("this is father\n");
                close(fd[0]); //关闭读取端

                //向管道写数据
                write(fd[1], "hello from father", strlen("hello from father"));

                wait(NULL);
        } else {
                printf("this is child\n");
                close(fd[1]); //关闭写入端
                read(fd[0], buf, sizeof(buf));  //从管道读数据
                printf("child print: %s\n", buf);
                exit(1);
        }


        return 0;
}

程序执行结果如下: 

 

命名管道(Named Pipes)的使用:

命名管道是一种具有持久性的管道,它以文件的形式存在于文件系统中,并允许无关进程之间进行通信。相比于匿名管道,命名管道允许不具有亲缘关系的进程之间进行通信。

创建命名管道

在Unix/Linux系统中,可以使用mkfifo()函数创建命名管道。命名管道创建后,会在文件系统中生成一个特殊类型的文件,它可以像普通文件一样被打开、读取和写入。

使用命名管道

使用命名管道和使用普通文件一样,可以使用文件I/O操作来读取和写入数据。不同的是,命名管道的数据读取和写入是以先进先出(FIFO)的方式进行的,即写入的数据按照写入的顺序从管道中读取出来。

特点

  • 命名管道是持久性的,创建后会一直存在于文件系统中,直到被显式删除。
  • 允许不具有亲缘关系的进程之间进行通信。
  • 数据按照写入的顺序从管道中读取出来,具有先进先出(FIFO)的特性。

 

示例

下面是一个简单的C语言示例,演示了如何创建和使用命名管道:

先介绍一下mkfifo:mkfifo 是用于创建命名管道(FIFO)的系统调用。在 Unix 和类 Unix 系统中,命名管道以文件的形式存在,可以用于不同进程之间进行通信。

mkfifo 函数原型

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

int mkfifo(const char *pathname, mode_t mode);

参数

  • pathname:要创建的命名管道的路径。
  • mode:管道的权限,类似于 openchmod 中使用的权限位。常用权限包括 0666(表示管道文件可读可写)。

返回值

  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 以指示错误。

 注意:

命名管道的读写操作是同步的,这意味着:

  • 写入进程会等待直到有读取进程打开管道进行读取。
  • 读取进程会等待直到有写入进程向管道写入数据。

这导致如果你先运行写入程序而没有相应的读取程序在运行,写入程序会阻塞,等待读取程序打开管道读取数据。同样地,如果你先运行读取程序而没有写入程序在运行,读取程序会阻塞,等待写入程序向管道写入数据。

为了避免这个问题,可以按以下步骤运行程序:

  1. 先运行读取程序 reader,使其准备好从管道读取数据。
  2. 然后运行写入程序 writer,向管道写入数据。
writer.c (写入程序)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_FILE "/tmp/my_fifo"

int main() {
    // 创建命名管道,权限模式为 0600
    if (mkfifo(FIFO_FILE, 0600) == -1) {
        perror("mkfifo failed");
        exit(EXIT_FAILURE);
    }

    // 打开命名管道以写入数据
    int fd = open(FIFO_FILE, O_WRONLY);
    if (fd == -1) {
        perror("open failed");
        exit(EXIT_FAILURE);
    }

    // 写入数据到命名管道
    const char *message = "Hello, Named Pipe!";
    write(fd, message, sizeof(message));

    // 关闭文件描述符
    close(fd);

    return 0;
}
reader.c (读取程序)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_FILE "/tmp/my_fifo"

int main() {
    char buffer[BUFSIZ];

    // 打开命名管道以读取数据
    int fd = open(FIFO_FILE, O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        exit(EXIT_FAILURE);
    }

    // 从命名管道读取数据
    read(fd, buffer, sizeof(buffer));
    printf("Received: %s\n", buffer);

    // 关闭文件描述符
    close(fd);

    // 删除命名管道文件
    unlink(FIFO_FILE);

    return 0;
}

程序运行结果:

 

 

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

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

相关文章

618快到了,送大家一款自动化脚本工具,一起薅羊毛

前言 一年一次的618活动来了&#xff0c;大家做好准备了&#xff0c;奇谈君为大家准备好用的618神器&#xff0c;解放双手&#xff0c;简单操作就可以把红包拿到手。 京淘自动助手 首次使用前需要进行设置 将手机的无障碍权限和悬浮窗权限打开 设置完成后&#xff0c;可以把…

编程实战:类C语法的编译型脚本解释器(四)总入口和使用方法

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 系列入口&#xff1a; 编程实战…

深入了解数据库设计中的规范化与反规范化

目录 零、前言 一、一些基本术语 二、关系模式 2.1. 什么是关系模式 2.2. 示例 三、数据依赖 3.1. 函数依赖 3.1.1. 完全函数依赖 3.1.2. 部分函数依赖 3.1.3. 传递函数依赖 3.2. 多值依赖 3.3. 连接依赖 四、规范化 4.1. 第一范式&#xff08;1NF&#xff09; …

Redis 性能管理

一、Redis 性能管理 #查看Redis内存使用 172.168.1.11:6379> info memory 1. 内存碎片率 操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存总量值 used_memory 计算得出。内存值 used_memory_rss 表示该进程所占物理内存的大小&#xff0c;即为操作系统分配给…

批量化处理和矩阵(torch)

左边是权重&#xff0c;右边是变量 高维可以看成二维的堆叠 总结&#xff1a;二维是一维的堆叠&#xff0c;三维是二维的堆叠。但似乎是为了引入矩阵&#xff0c;本来应该是左上角是第一组权重和第一组变量的乘积这种表示表示来着&#xff0c;最后成了和列向量乘积&#xff…

Python | Leetcode Python题解之第111题二叉树的最小深度

题目&#xff1a; 题解&#xff1a; class Solution:def minDepth(self, root: TreeNode) -> int:if not root:return 0que collections.deque([(root, 1)])while que:node, depth que.popleft()if not node.left and not node.right:return depthif node.left:que.appen…

认识K8s集群的声明式资源管理方法

前言 Kubernetes 集群的声明式资源管理方法是当今云原生领域中的核心概念之一&#xff0c;使得容器化应用程序的部署和管理变得更加高效和可靠。本文将认识了解 Kubernetes 中声明式管理的相关理念、实际应用以及优势。 目录 一、管理方法介绍 1. 概述 2. 语法格式 2.1 管…

猫头虎 解析:为什么AIGC在国内适合做TOB,在国外适合做TOC?

猫头虎 解析&#xff1a;为什么AIGC在国内适合做TOB&#xff0c;在国外适合做TOC&#xff1f; 博主 猫头虎 的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面…

掩码生成蒸馏——知识蒸馏

摘要 https://arxiv.org/pdf/2205.01529 知识蒸馏已成功应用于各种任务。当前的蒸馏算法通常通过模仿教师的输出来提高学生的性能。本文表明&#xff0c;教师还可以通过指导学生的特征恢复来提高学生的表示能力。从这一观点出发&#xff0c;我们提出了掩码生成蒸馏&#xff08…

《图解支付系统设计与实现》电子书_V20240525

相较于上次公开发布的V20240503版本&#xff0c;变更内容如下&#xff1a; 根据掘金网友zz67373&#xff08;李浩铭&#xff09;的勘误建议&#xff0c;优化了部分描述。增加&#xff1a;金额处理规范&#xff0c;低代码报文网关实现完整代码&#xff0c;分布式流控等内容。扩…

Golang | Leetcode Golang题解之第111题二叉树的最小深度

题目&#xff1a; 题解&#xff1a; func minDepth(root *TreeNode) int {if root nil {return 0}queue : []*TreeNode{}count : []int{}queue append(queue, root)count append(count, 1)for i : 0; i < len(queue); i {node : queue[i]depth : count[i]if node.Left …

(十一)统计学基础练习题五(50道选择题)

本文整理了统计学基础知识相关的练习题&#xff0c;共50道&#xff0c;适用于想巩固统计学基础或备考的同学。来源&#xff1a;如荷学数据科学题库&#xff08;技术专项-统计学二&#xff09;。序号之前的题请看往期文章。 201&#xff09; 202&#xff09; 203&#xff09; 2…

LeetCode 第131场双周赛个人题解

100309. 求出出现两次数字的 XOR 值 原题链接 求出出现两次数字的 XOR 值 - 力扣 (LeetCode) 竞赛 思路分析 签到题&#xff0c;一次遍历 AC代码 class Solution:def duplicateNumbersXOR(self, nums: List[int]) -> int:cnt Counter(nums)res 0st set(nums)for x …

linux系统环境—基础开发工具

目录 1. yum工具&#xff0c;进行软件安装 示例&#xff1a;下载第一个软件 2. vim编辑器&#xff0c;学会vim的简单配置 vim的基本操作 vim末行模式命令集 插入模式与普通编辑器差不多。无命令集合 3. gcc/g编译器的使用&#xff0c;并了解其过程&#xff0c;原理 1预…

脚注:书籍的小秘密,躲藏在脚注间

脚注&#xff1a;书籍的小秘密&#xff0c;躲藏在脚注间 脚注是一种在文本中提供补充信息、引用出处或注解的方式&#xff0c;有助于读者更全面地理解文中内容&#xff0c;并为进一步研究提供参考和跳转点。 在一书本中&#xff0c;脚注是额外提供给读者的文字信息&#xff0…

java:static关键字用法

在静态方法中不能访问类的非静态成员变量和非静态方法&#xff0c; 因为非静态成员变量和非静态方法都必须依赖于具体的对象才能被调用。 从上面代码里看出&#xff1a; 1.静态方法不能调用非静态成员变量。静态方法test2()中调用非静态成员变量address&#xff0c;编译失败…

Java进阶学习笔记19——内部类

1、 内部类&#xff1a; 是类中五大成分之一&#xff08;成员变量、方法、构造函数、内部类、代码块&#xff09;&#xff0c;如果一个类定义在另一个 类的内部&#xff0c;这个类就是内部类。 场景&#xff1a;当一个类的内部&#xff0c;包含了一个完整的事物&#xff0c;且…

[笔试训练](三十三)097:跳台台阶扩展问题098:包含不超过两种字符的最长子串099:字符串的排列

目录 097:跳台台阶扩展问题 098:包含不超过两种字符的最长子串 099:字符串的排列 097:跳台台阶扩展问题 题目链接:跳台阶扩展问题_牛客题霸_牛客网 (nowcoder.com) 题目&#xff1a; 题解&#xff1a; 规律题: 1.跳上n级台阶的跳法等于前面1~(n-1)级台阶跳法的总和1。 2.跳…

[5] CUDA线程调用与存储器架构

CUDA线程调用与存储器架构 前几节简单讲了如何编写CUDA程序&#xff0c;利用GPU的处理能力并行执行多个线程和块。之前所有程序里的线程是相互独立的&#xff0c;没有多个线程之间的通信多是实际应用程序需要中间线程之间的通信&#xff0c;本文将仔细讲解线程调用以及CUDA的分…

Gradle的settings.gradle.kts你真的理解吗?

你还在用.gradle文件吗&#xff1f;例如build.gradle、settings.gradle&#xff0c;那么你就out了。现在我们有必要了解一下kts脚本了。在Android项目中&#xff0c;默认有3个文件可以替换成kts脚本&#xff0c;即project的build.gradle、app模块的build.gradle和project的sett…