基于信号量与共享内存实现客户与服务器进程通信

基于信号量与共享内存实现客户与服务器进程通信

发送进程

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>#define SHARED_MEM_NAME "/shared_mem"
#define SEM_NAME "/sem_sync"
#define MEM_SIZE 1024
#define END_STRING "END"int main() {int shm_fd;void *shared_mem;sem_t *sem;shm_fd = shm_open(SHARED_MEM_NAME, O_CREAT | O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(1);}ftruncate(shm_fd, MEM_SIZE);shared_mem = mmap(0, MEM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);if (shared_mem == MAP_FAILED) {perror("mmap failed");exit(1);}sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);if (sem == SEM_FAILED) {perror("sem_open failed");exit(1);}char buffer[MEM_SIZE];while (1) {printf("输入字符串:");fgets(buffer, MEM_SIZE, stdin);buffer[strcspn(buffer, "\n")] = 0;  // 去掉换行符strncpy((char *)shared_mem, buffer, MEM_SIZE);sem_post(sem);if (strcmp(buffer, END_STRING) == 0) {break;}}munmap(shared_mem, MEM_SIZE);close(shm_fd);sem_close(sem);return 0;
}

详细解析

0,头文件与宏定义

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

这些头文件包含了程序中使用的标准库和系统库:

  • stdio.hstdlib.h:提供基本的输入/输出功能(如 printffgets)以及内存管理功能(如 exit)。

  • string.h:提供字符串操作函数,如 strncpystrcmp

  • unistd.h:提供对 POSIX 操作系统 API 的访问,如 close 函数。

  • fcntl.h:用于文件控制操作,如 shm_open 中的标志。

  • sys/mman.h:包含内存映射相关的函数,如 mmapshm_open

  • semaphore.h:提供信号量相关的功能,用于进程同步。

#define SHARED_MEM_NAME "/shared_mem"
#define SEM_NAME "/sem_sync"
#define MEM_SIZE 1024
#define END_STRING "END"
  • SHARED_MEM_NAME:共享内存的名称。名称必须以斜杠 / 开头,以表示这是一个 POSIX 共享内存对象。
  • SEM_NAME:信号量的名称,用于同步客户端和服务器进程。
  • MEM_SIZE:共享内存的大小,以字节为单位。在这里,大小为 1024 字节(1 KB)。
  • END_STRING:用于判断是否结束程序的特殊字符串 “END”。

1,shm_fd

shm_fd = shm_open(SHARED_MEM_NAME, O_CREAT | O_RDWR, 0666);

SHARED_MEM_NAME:共享内存的名称。名称必须以斜杠 / 开头,以表示这是一个 POSIX 共享内存对象,这里我们使用 /shared_mem

shm_open 函数包含在 sys/mman.h 头文件中,用于创建或打开一个 POSIX 共享内存对象。

其中 O_CREAT | O_RDRW 标志如果共享内存对象不存在就创建它,并且以可读可写模式打开它。

2,

0666 为权限设置,表示共享内存对象对所有用户可读可写。

错误处理:如果 shm_open 失败,返回 -1,并通过 perror 打印错误信息,然后调用 exit(1) 终止程序。

2,ftruncate

ftruncate(shm_fd, MEM_SIZE);

3,mmap

    shared_mem = mmap(0, MEM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);if (shared_mem == MAP_FAILED) {perror("mmap failed");exit(1);}

设置共享内存对象的大小为 MEM_SIZE 字节,即 1024 字节。

  • mmap:将共享内存映射到进程的地址空间,以便我们可以像使用普通内存一样访问它。
    • 0:让操作系统选择共享内存的映射地址。
    • MEM_SIZE:映射的大小(1024 字节)。
    • PROT_WRITE:指定映射区域可写。
    • MAP_SHARED:其他进程对共享内存的修改是可见的,并且会影响到共享内存的实际内容。
    • shm_fd:共享内存对象的文件描述符。
    • 0:偏移量,表示从共享内存的开头开始映射。
  • 错误处理:如果 mmap 失败,返回 MAP_FAILED,并打印错误信息,然后终止程序。

4,sem_open

sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);
if (sem == SEM_FAILED) {perror("sem_open failed");exit(1);
}
  • sem_open:创建或打开一个命名信号量。
    • SEM_NAME:信号量的名称。
    • O_CREAT:如果信号量不存在,则创建它。
    • 0666:权限设置,表示信号量对所有用户可访问。
    • 0:信号量的初始值为 0(表示不可用状态)。
  • 错误处理:如果 sem_open 失败,返回 SEM_FAILED,并打印错误信息,然后终止程序。

5,主循环

char buffer[MEM_SIZE];while (1) {printf("输入字符串:");fgets(buffer, MEM_SIZE, stdin);buffer[strcspn(buffer, "\n")] = 0;  // 去掉换行符strncpy((char *)shared_mem, buffer, MEM_SIZE);sem_post(sem);if (strcmp(buffer, END_STRING) == 0) {break;}}

从键盘中读入字符串,然后去掉换行符。

strcspn 的作用是找到 \n 的位置,然后该位置换为 \0,表示字符串结尾。

strncpy 表示将 buffer 中的内容复制到 shared_mem 中。

sem_post 表示增加信号量的值,表示共享内存中有新的数据可读,这个操作通知服务器进程可以读取共享内存的内容。

我们重复这个循环,直到输入的字符串为 END 时终止。

6,释放资源

munmap(shared_mem, MEM_SIZE);
close(shm_fd);
sem_close(sem);

munmap : 接触共享内存映射,释放地址空间

close : 关闭共享内存的文件描述符

sem_close : 关闭信号量

接收进程

代码与发送进程类似,故不做解析。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>#define SHARED_MEM_NAME "/shared_mem"
#define SEM_NAME "/sem_sync"
#define MEM_SIZE 1024
#define END_STRING "END"int main() {int shm_fd;void *shared_mem;sem_t *sem;shm_fd = shm_open(SHARED_MEM_NAME, O_RDONLY, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(1);}shared_mem = mmap(0, MEM_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);if (shared_mem == MAP_FAILED) {perror("mmap failed");exit(1);}sem = sem_open(SEM_NAME, 0);if (sem == SEM_FAILED) {perror("sem_open failed");exit(1);}char buffer[MEM_SIZE];while (1) {sem_wait(sem);strncpy(buffer, (char *)shared_mem, MEM_SIZE);buffer[MEM_SIZE - 1] = '\0';  // 确保字符串以NULL结尾printf("读取字符串:%s\n", buffer);if (strcmp(buffer, END_STRING) == 0) {break;}}munmap(shared_mem, MEM_SIZE);close(shm_fd);sem_close(sem);return 0;
}

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

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

相关文章

【AI大模型引领变革】探索AI如何重塑软件开发流程与未来趋势

文章目录 每日一句正能量前言流程与模式介绍【传统软件开发 VS AI参与的软件开发】一、传统软件开发流程与模式二、AI参与的软件开发流程与模式三、AI带来的不同之处 结论 AI在软件开发流程中的优势、挑战及应对策略AI在软件开发流程中的优势面临的挑战及应对策略 结论 后记 每…

机器学习的全面解析:从基础到应用

引言&#xff1a;机器学习的核心地位 机器学习&#xff08;Machine Learning, ML&#xff09;是人工智能&#xff08;AI&#xff09;的核心分支&#xff0c;它通过算法使计算机能够从数据中学习并进行预测或决策。机器学习技术在许多领域都有广泛应用&#xff0c;包括推荐系统、…

Chapter 2 - 16. Understanding Congestion in Fibre Channel Fabrics

Transforming an I/O Operation to FC frames A read or write I/O operation (Figure 2-28) between an initiator and a target undergoes a series of transformations before being transmitted on a Fibre Channel link. 启动程序和目标程序之间的读取或写入 I/O 操作(图…

如何解决Java EasyExcel 导出报内存溢出

如何解决Java EasyExcel 导出报内存溢出 EasyExcel大数据量导出常见方法 1. 分批写入 EasyExcel支持分批写入数据&#xff0c;可以将数据分批加载到内存中&#xff0c;分批写入Excel文件&#xff0c;避免一次性将大量数据加载到内存中。 示例代码&#xff1a; String fileNa…

Qt 的事件投递机制:从基础到实战

在 Qt 开发中&#xff0c;事件系统是核心概念之一&#xff0c;几乎每一个 GUI 应用程序都依赖于它来响应用户操作和系统通知。对于有一定 Qt 基础但首次接触事件投递 (QCoreApplication::postEvent) 的开发者而言&#xff0c;理解事件投递机制尤为重要。这篇博客将带你从基本概…

QDialog中,reject()和close()区别

1. reject()函数 reject()是QDialog类中的一个槽函数&#xff0c;用于以“拒绝”的方式关闭对话框。它通常与对话框的“取消”操作相关联。当调用reject()时&#xff0c;会发出rejected()信号。 行为细节&#xff1a; 从模态对话框的角度来看&#xff0c;当模态对话框调用reje…

【036】基于51单片机五子棋游戏机【Proteus仿真+Keil程序+报告+原理图】

☆、设计硬件组成&#xff1a;51单片机最小系统LCD12864液晶显示按键控制。 1、设计采用STC89C51/52、AT89C51/52、AT89S51/52作为主控芯片&#xff0c;采用LCD12864液晶作为显示&#xff1b; 2、游戏有 人机对战 和 玩家对战 两种模式&#xff0c;玩家白子先下&#xff1b; …

HTML通过JavaScript获取访问连接,IP和端口

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>Get IP Address</title> <script> function displayURL() { var url window.location.href; // 获取当…

VMWARE虚拟交换机的负载平衡算法

一、基于源虚拟端口的路由 虚拟交换机可根据 vSphere 标准交换机或 vSphere Distributed Switch 上的虚拟机端口 ID 选择上行链路。 基于源虚拟端口的路由是 vSphere 标准交换机和 vSphere Distributed Switch 上的默认负载平衡方法。 ESXi主机上运行的每个虚拟机在虚拟交换…

slam里的体素滤波

SLAM系统通常需要处理大量的传感器数据&#xff0c;如激光雷达&#xff08;LiDAR&#xff09;、相机等获取的数据&#xff0c;这些数据往往包含了大量的冗余信息和噪声。为了提高SLAM系统的效率和准确性&#xff0c;数据预处理是非常重要的一步&#xff0c;体素滤波就是一种常用…

web——sqliabs靶场——第十二关——(基于错误的双引号 POST 型字符型变形的注入)

判断注入类型 a OR 1 1# 发现没有报错 &#xff0c;说明单引号不是闭合类型 测试别的注入条件 a) OR 1 1# a)) OR 1 1# a" OR 11 发现可以用双引号闭合 发现是")闭合 之后的流程还是与11关一样 爆破显示位 先抓包 是post传参&#xff0c;用hackbar来传参 unam…

AI时代,百度的三大主义

现实主义、长期主义、理想主义。 定焦One&#xff08;dingjiaoone&#xff09;原创 作者 | 苏琦 郑浩钧 编辑 | 魏佳 “人工智能很像是一次新的工业革命&#xff0c;这意味着它不会三五年就结束&#xff0c;也不会一两年就出现‘超级应用’&#xff0c;它更像是三五十年对于整…

C++基础入门篇

C入门 第一个C程序 首先C兼容c语言&#xff0c;所以由c语言实现的内容仍然可以在C中实现&#xff0c;但是c语言的文件后缀是.c但是C的后缀是.cpp。vs对于cpp文件使用C编译器编译&#xff0c;linux需要用g编译而不是gcc #include<stdio> int main() {printf("hello…

基于YOLOv11的火焰实时检测系统(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

100多种【基于YOLOv8/v10/v11的目标检测系统】目录&#xff08;pythonpyside6界面系统源码可训练的数据集也完成的训练模型 摘要&#xff1a; 本文提出了一种基于YOLOv11算法的火灾检测系统&#xff0c;利用1852张图片&#xff08;1647张训练集&#xff0c;205张验证集&#…

Python入门(10)--面向对象进阶

Python面向对象进阶 &#x1f680; 1. 继承与多态 &#x1f504; 1.1 继承基础 class Animal:def __init__(self, name, age):self.name nameself.age agedef speak(self):passdef describe(self):return f"{self.name} is {self.age} years old"class Dog(Anim…

算法——两两交换链表中的节点(leetcode24)

这是一道对于链表节点进行操作的题目非常考验对于链表操作的基本功&#xff1b; 解法: 本题的解法结合下图来进一步解释 创建一个虚拟节点指向头结点以便使代码逻辑看起来更为简便且操作节点容易,定义cur是为了方便找到cur之后的两个节点进行交换操作定义pre和aft是为了保存执…

【提效工具开发】管理Python脚本执行系统实现页面展示

Python脚本执行&#xff1a;工具管理Python脚本执行系统 背景 在现代的软件开发和测试过程中&#xff0c;自动化工具和脚本的管理变得至关重要。为了更高效地管理工具、关联文件、提取执行参数并支持动态执行Python代码&#xff0c;我们设计并实现了一套基于Django框架的工具…

鸿蒙开发:ForEach中为什么键值生成函数很重要

前言 在列表组件使用的时候&#xff0c;如List、Grid、WaterFlow等&#xff0c;循环渲染时都会使用到ForEach或者LazyForEach&#xff0c;当然了&#xff0c;也有单独使用的场景&#xff0c;如下&#xff0c;一个很简单的列表组件使用&#xff0c;这种使用方式&#xff0c;在官…

Figma插件指南:12款提升设计生产力的插件

在当今的设计领域&#xff0c;Figma已经成为许多UI设计师和团队的首选原型和数字设计软件。随着Figma的不断更新和插件库的扩展&#xff0c;这些工具极大地提升了设计工作的效率。本文将介绍12款实用的Figma插件&#xff0c;帮助你在UI设计中更加高效。 即时AI 即时AI利用先进…

揭秘云计算 | 5、关于云计算效率的讨论

一、 公有云效率更高&#xff1f; 解&#xff1a;公有云具有更高的效率。首先我们需要知道效率到底指的是什么。这是个亟须澄清的概念。在这里效率是指云数据中心&#xff08;我们将在后文中介绍其定义&#xff09;中的IT设备资源利用率&#xff0c;其中最具有代表性的指标就是…