Linux之IPC通信共享内存与消息队列、管道、信号量、socket内存拷贝实例总结(六十二)

本文主要是介绍Linux之IPC通信共享内存与消息队列、管道、信号量、socket内存拷贝实例总结(六十二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:理解IPC通信消息队列、管道、socket两次内存拷贝与共享内存一次内存拷贝。

2.IPC通信消息队列、管道、socket、共享内存介绍

  • 在Linux和Android中,进程间通信(IPC)的方式有很多种,包括管道(Pipe)、消息队列(Message Queue)、共享内存(Shared Memory)、信号量(Semaphore)、套接字(Socket)等。其中,管道、消息队列、套接字都需要进行两次内存拷贝,而共享内存只需要一次内存拷贝。

1. 两次内存拷贝的IPC方式:

  • 管道(Pipe): 当一个进程向管道中写入数据时,数据首先会被拷贝到内核缓冲区,然后当另一个进程从管道中读取数据时,数据会从内核缓冲区拷贝到该进程的内存空间。这就是两次内存拷贝。

  • 消息队列(Message Queue): 消息队列的工作方式与管道类似,数据在发送和接收时都需要经过内核缓冲区,因此也需要两次内存拷贝。

  • 套接字(Socket): 套接字在发送和接收数据时,数据也需要经过内核缓冥区,因此也需要两次内存拷贝。

2. 一次内存拷贝的IPC方式:

  • 共享内存(Shared Memory): 共享内存是最快的IPC方式,因为进程是直接对内存进行操作,数据不需要在进程和内核之间进行拷贝。但是,由于多个进程可以同时操作同一块内存,因此需要使用信号量等同步机制来防止数据的不一致。

3.总结

  • 一次内存拷贝:
    一次内存拷贝是指数据在用户空间和内核空间之间只进行了一次拷贝。在Linux和Android中,使用共享内存(shared memory)实现IPC通信是一种一次内存拷贝的方式。共享内存允许多个进程共享同一块物理内存,因此数据被写入内核空间后,其他进程可以直接在内存中读取数据,避免了多次拷贝的开销。

  • 两次内存拷贝:
    两次内存拷贝指数据在用户空间和内核空间之间进行了两次拷贝。在Linux和Android中,使用Socket、管道(pipe)和消息队列(message queue)进行IPC通信会涉及两次内存拷贝。

3.代码实例

1.共享内存进行一次内存拷贝

#include <iostream>
#include <sys/shm.h>
#include <cstring>int main() {key_t key = ftok("/tmp", 'S');int shmid = shmget(key, 1024, 0666 | IPC_CREAT);char *data = (char*)shmat(shmid, nullptr, 0);std::string message = "Hello, IPC using shared memory!";std::memcpy(data, message.c_str(), message.size());shmdt(data);shmctl(shmid, IPC_RMID, nullptr);return 0;
}

2.Socket进行两次内存拷贝

// 服务器端
#include <iostream>
#include <sys/socket.h>
#include <cstring>int main() {int server_sock = socket(AF_INET, SOCK_STREAM, 0);// 绑定和监听int client_sock = accept(server_sock, nullptr, nullptr);std::string message = "Hello, IPC using sockets!";send(client_sock, message.c_str(), message.size(), 0);close(client_sock);close(server_sock);return 0;
}// 客户端
#include <iostream>
#include <sys/socket.h>
#include <cstring>int main() {int client_sock = socket(AF_INET, SOCK_STREAM, 0);// 连接服务器char buffer[1024];recv(client_sock, buffer, sizeof(buffer), 0);std::cout << "Message received from server: " << buffer << std::endl;close(client_sock);return 0;
}

3.管道进行两次内存拷贝

#include <iostream>
#include <unistd.h>
#include <cstring>int main() {int pipe_fds[2];if (pipe(pipe_fds) == -1) {std::cerr << "Failed to create pipe" << std::endl;return 1;}const char* message = "Hello, IPC using pipes!";const size_t len = strlen(message);if (write(pipe_fds[1], message, len) != static_cast<ssize_t>(len)) {std::cerr << "Failed to write to pipe" << std::endl;return 1;}char buffer[64];ssize_t bytes_read = read(pipe_fds[0], buffer, sizeof(buffer));if (bytes_read == -1) {std::cerr << "Failed to read from pipe" << std::endl;return 1;}std::cout << "Message read from pipe: " << std::string(buffer, bytes_read) << std::endl;close(pipe_fds[0]);close(pipe_fds[1]);return 0;
}

4.消息队列进行两次内存拷贝

#include <iostream>
#include <cstring>
#include <sys/msg.h>struct Message {long type;char text[100];
};int main() {key_t key = ftok("/tmp", 'Q');int msgid = msgget(key, 0666 | IPC_CREAT);Message message;message.type = 1;std::strcpy(message.text, "Hello, IPC using message queues!");msgsnd(msgid, &message, sizeof(message.text), 0);msgrcv(msgid, &message, sizeof(message.text), 1, 0);std::cout << "Message received from message queue: " << message.text << std::endl;msgctl(msgid, IPC_RMID, nullptr);return 0;
}

5.信号量进行两次内存拷贝

#include <iostream>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>int main() {key_t key = ftok("/tmp", 'S');int semid = semget(key, 1, IPC_CREAT | 0666);if (semid == -1) {std::cerr << "Failed to create semaphore" << std::endl;return 1;}sembuf acquire = {0, -1, SEM_UNDO};sembuf release = {0, 1, SEM_UNDO};if (semop(semid, &acquire, 1) == -1) {std::cerr << "Failed to acquire semaphore" << std::endl;return 1;}// Critical section - perform operations that require exclusive accessstd::string message = "Hello, IPC using semaphores!";// Perform operations on the shared resourceif (semop(semid, &release, 1) == -1) {std::cerr << "Failed to release semaphore" << std::endl;return 1;}return 0;
}

这篇关于Linux之IPC通信共享内存与消息队列、管道、信号量、socket内存拷贝实例总结(六十二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/381407

相关文章

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

Redis Pipeline(管道) 详解

《RedisPipeline(管道)详解》Pipeline管道是Redis提供的一种批量执行命令的机制,通过将多个命令一次性发送到服务器并统一接收响应,减少网络往返次数(RTT),显著提升执行效率... 目录Redis Pipeline 详解1. Pipeline 的核心概念2. 工作原理与性能提升3. 核

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

Linux命令之firewalld的用法

《Linux命令之firewalld的用法》:本文主要介绍Linux命令之firewalld的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux命令之firewalld1、程序包2、启动firewalld3、配置文件4、firewalld规则定义的九大

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

Linux之计划任务和调度命令at/cron详解

《Linux之计划任务和调度命令at/cron详解》:本文主要介绍Linux之计划任务和调度命令at/cron的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux计划任务和调度命令at/cron一、计划任务二、命令{at}介绍三、命令语法及功能 :at

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文