Linux进程间通信---使用【共享内存+信号量+消息队列】的组合来实现服务器进程与客户进程间的通信

IPC结合实现进程间通信实例

下面将使用【共享内存+信号量+消息队列】的组合来实现服务器进程与客户进程间的通信。

  • 共享内存用来传递数据;
  • 信号量用来同步;
  • 消息队列用来 在客户端修改了共享内存后通知服务器读取。

server.c:服务端接收信息

#include <sys/ipc.h>    // 包含进程间通信相关的头文件
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义消息队列中的消息结构
struct msgbuf {long mtype; // 消息类型char mtext;  // 消息文本
};// 定义信号量联合体,用于semctl函数
union semun {int val;            // 用于SETVAL命令struct semid_ds *buf; // 用于IPC_STAT和IPC_SET命令
};// 删除IPC资源的函数
void delet_IPC(int msgid, char *shm, int shmid, int semid) {shmdt(shm);// 断开共享内存 // 删除共享内存if (shmctl(shmid, IPC_RMID, NULL) == -1){perror("Failed to delete shared memory");}// 删除消息队列if (msgctl(msgid, IPC_RMID, NULL) == -1){perror("Failed to delete message queue");}// 删除信号量集if (semctl(semid, 0, IPC_RMID) == -1){perror("Failed to delete semaphore");}
}// P操作:等待信号量
void p_handler(int semid) {struct sembuf set;set.sem_num = 0;set.sem_op = -1; // 执行P操作set.sem_flg = SEM_UNDO;semop(semid, &set, 1);
}// V操作:释放信号量
void v_handler(int semid) {struct sembuf set;set.sem_num = 0;set.sem_op = 1; // 执行V操作set.sem_flg = SEM_UNDO;semop(semid, &set, 1);
}int main() {key_t key;              // 用于ftok的键char *shm;               // 共享内存的指针int flag = 1;           // 控制循环的标记int msgid, shmid, semid; // 消息队列、共享内存和信号量的IDstruct msgbuf rcvmsg;   // 定义接收消息的缓冲区union semun initsem;	// 定义信号量的初始化联合体// 获取或创建key    if ((key = ftok(".", 'a')) == -1){perror("ftok failed");exit(EXIT_FAILURE);}// 创建或获取消息队列if ((msgid = msgget(key, IPC_CREAT | 0666)) == -1) {perror("msgget failed");exit(EXIT_FAILURE);}// 创建或获取共享内存if ((shmid = shmget(key, 1024, IPC_CREAT | 0666)) == -1) {perror("shmget failed");exit(EXIT_FAILURE);}// 挂载共享内存 if ((shm = (char *)shmat(shmid, 0, 0)) == (void *)(-1)) {perror("shmat failed");exit(EXIT_FAILURE);}// 创建或获取信号量集if ((semid = semget(key, 1, IPC_CREAT | 0666)) == -1) {perror("semget failed");exit(EXIT_FAILURE);}// 初始化信号量的值为1initsem.val = 1;if (semctl(semid, 0, SETVAL, initsem) == -1) {perror("semctl SETVAL failed");}while (flag) {// 接收消息msgrcv(msgid, &rcvmsg, sizeof(struct msgbuf), 888, 0);// 根据消息内容执行不同的操作switch (rcvmsg.mtext) {case 'r': // 读操作printf("read: ");p_handler(semid); // 执行P操作printf("%s\n", shm); // 打印共享内存中的内容v_handler(semid); // 执行V操作break;case 'q': // 退出操作printf("quit\n");// 删除所有IPC资源delet_IPC(msgid, shm, shmid, semid);flag = 0; // 设置退出标志break;}}return 0;
}

client.c客户端发送消息

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <string.h>struct msgbuf {long mtype; // 消息类型char mtext; // 消息文本
};// P操作:等待信号量,直到信号量的值大于0,然后将其减1
void p_handler(int semid) {struct sembuf set;set.sem_num = 0;set.sem_op = -1;set.sem_flg = SEM_UNDO;semop(semid, &set, 1);
}// V操作:释放信号量,将其值加1,并可能唤醒等待该信号量的其他进程
void v_handler(int semid) {struct sembuf set;set.sem_num = 0;set.sem_op = 1;set.sem_flg = SEM_UNDO;if (semop(semid, &set, 1) == -1){perror("V operation failed");}
}int main() {key_t key;char *shm;char str[128];int flag = 1;int msgid, shmid, semid;struct msgbuf readmsg;// 创建或获取IPC的键if ((key = ftok(".", 'a')) < 0){perror("ftok failed");exit(EXIT_FAILURE);}// 获取消息队列IDif ((msgid = msgget(key, 0666 | IPC_CREAT)) == -1){perror("msgget failed");exit(EXIT_FAILURE);}// 获取共享内存IDif ((shmid = shmget(key, 1024, 0666 | IPC_CREAT)) == -1){perror("shmget failed");exit(EXIT_FAILURE);}// 将共享内存附加到当前进程的地址空间shm = (char *)shmat(shmid, 0, 0);if (shm == (char *)(-1)){perror("shmat failed");exit(EXIT_FAILURE);}// 获取信号量IDif ((semid = semget(key, 0, 0666 | IPC_CREAT)) == -1){perror("semget failed");exit(EXIT_FAILURE);}// 打印菜单printf("---------------------------------------\n");printf("--                IPC                --\n");printf("--  input w :write data send client  --\n");printf("--  input q :quit procedure          --\n");printf("---------------------------------------\n");// 主循环while (flag) {char c;printf("input:");scanf("%c", &c); // 读取用户输入switch (c) {// 写操作case 'w':getchar(); // 消耗掉scanf后的换行符p_handler(semid); // 执行P操作memset(str, 0, sizeof(str)); // 清空字符串printf("write:\n");// 读取用户输入的字符串fgets(str, sizeof(str), stdin); // 使用fgets代替gets以避免缓冲区溢出strcpy(shm, str); // 将用户输入的字符串复制到共享内存v_handler(semid); // 执行V操作// 发送消息给读者,告知有新数据写入共享内存readmsg.mtype = 888;readmsg.mtext = 'r';msgsnd(msgid, &readmsg, sizeof(struct msgbuf), 0);break;// 退出操作case 'q':printf("quit\n");// 清除输入缓冲区直到遇到换行符或文件结束符while ((c = getchar()) != '\n' && c != EOF);// 发送退出消息readmsg.mtype = 888;readmsg.mtext = 'q';msgsnd(msgid, &readmsg, sizeof(struct msgbuf), 0);flag = 0; // 设置退出标志break;// 输入错误处理default:printf("%c input error\n", c);// 清除输入缓冲区while ((c = getchar()) != '\n' && c != EOF);break;}}return 0;
}

运行结果:左侧为服务端,接收来自客户端的消息,右侧为客户端,发送指令然后传递消息。
在这里插入图片描述

参考文章:【Linux编程】进程间通信(IPC)

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

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

相关文章

如何解除内存卡的写保护并格式化为exFAT文件系统

最近有客户提问内存卡提示写保护&#xff0c;且无法格式化为exFAT格式的问题&#xff0c;可能是由于多种原因引起的。以下是一些可能的解决方法&#xff1a; 1. 检查物理写保护开关 一些SD卡和MicroSD卡适配器上有一个小的物理开关&#xff0c;可以启用或禁用写保护。确保这个…

C# WPF 读写CAN数据

C# WPF 读写CAN数据 CAN 分析仪 分析仪资料下载 官方地址&#xff1a;https://www.zhcxgd.com/1.html CSDN&#xff1a; 项目配置 复制Dll库文件 文件在上面的资料里面 设置不安全代码 CAN C#工具类 CAN_Tool.cs using Microsoft.VisualBasic; using System; using Sys…

任务3.8.2 利用RDD计算总分与平均分

实战&#xff1a;使用RDD 计算学生成绩的总分与平均分 项目背景 本项目旨在利用 Apache Spark 的强大数据处理能力&#xff0c;对存储在 HDFS 上的学生成绩文件进行处理&#xff0c;计算每个学生的总分和平均分。 项目目标 读取存储在 HDFS 上的成绩文件。计算每个学生的总…

MySQL 触发器(实验报告)

一、实验名称&#xff1a; 触发器 二、实验日期&#xff1a; 2024 年 6月 8日 三、实验目的&#xff1a; 掌握MySQL触发器的创建及调用&#xff1b; 四、实验用的仪器和材料&#xff1a; 硬件&#xff1a;PC电脑一台&#xff1b; 配置&#xff1a;内存&#xff0c;…

学习笔记丨嵌入式BI分析的12个关键功能

编者注&#xff1a;以下内容节选编译自嵌入式分析厂商Qrvey发表的《What is Embedded Analytics?》&#xff08;什么是嵌入式分析&#xff09;一文&#xff0c;作者为Qrvey产品市场主管Brian Dreyer。 什么是嵌入式分析&#xff1f; 嵌入式分析是指能够将数据分析的特性和功…

编程里len是什么意思:深度解析与应用探讨

编程里len是什么意思&#xff1a;深度解析与应用探讨 在编程的世界中&#xff0c;每一个函数和操作符都承载着特定的意义和功能。其中&#xff0c;len 作为一个常见的函数&#xff0c;在多种编程语言中都扮演着重要的角色。那么&#xff0c;len 到底是什么意思呢&#xff1f;本…

用ChatGPT 4o画漂亮的燃尽图代码

把代码给ChatGPT&#xff0c;然后他就会帮我生成出来了。 而且图是动态的&#xff0c;可以调整颜色文字之类的内容 # Given data for Sprint 5 Progress data_sprint_5 {User Story: [BEAN-40, BEAN-42, BEAN-41, BEAN-22, BEAN-33, BEAN-44, BEAN-10, BEAN-26, BEAN-37, BEA…

【SQL边干边学系列】07高级问题-3

文章目录 前言回顾高级问题41.逾期订单42.逾期订单-哪些员工&#xff1f;43.逾期订单与总订单相比44.逾期订单与总订单相比 - 丢失的员工45.逾期订单与总订单相比 - 修复null46.逾期订单与总订单之间的百分比47.逾期订单与总订单相比 - 修正decimal 答案41.逾期订单42.逾期订单…

一文了解localStorage 和 sessionStorage

文章导读&#xff1a;AI 辅助学习前端&#xff0c;包含入门、进阶、高级部分前端系列内容&#xff0c;当前是 JavaScript 的部分&#xff0c;瑶琴会持续更新&#xff0c;适合零基础的朋友&#xff0c;已有前端工作经验的可以不看&#xff0c;也可以当作基础知识回顾。 这篇文章…

Linux - 复盘一次句柄数引发的故障

文章目录 Pre&#xff08;内核、用户、进程&#xff09;句柄数设置问题 shell修复 Pre Linux - 深入理解/proc虚拟文件系统&#xff1a;从基础到高级 &#xff08;内核、用户、进程&#xff09;句柄数设置 在Linux系统中&#xff0c;进程打开的最大句柄数可以通过多种方式配置…

第二证券:大牛股连续七跌停,上市公司坐不住了!机构抄底

6月12日&#xff0c;沪深股市双双飘红。但是&#xff0c;从前的大牛股松炀资源(603863)&#xff0c;却依然跌停收盘。这也是公司股价近日来的接连第七个跌停板。 龙虎榜显现&#xff0c;6月12日&#xff0c;松炀资源全天换手率10.38%&#xff0c;成交额3.45亿元。当天&#xf…

沉降观测点的定义、重要性、建设与选择

沉降观测点&#xff0c;简称沉降点&#xff0c;是指在建筑物、构筑物或地基等结构物上设置的用于测量其垂直位移(沉降)的特定位置。这些点通常被标记并安装相应的监测设备&#xff0c;以便长期、连续地监测结构物的沉降情况。 点击输入图片描述&#xff08;最多30字&#xff09…

炒股的另外一种思路

曾经偶然机会&#xff0c;买了 h 一只股票放了七年左右&#xff0c;不多但是让我看到另外一种投资方法 整个经济中&#xff0c;有些公司是你想去但是可能没机会去的&#xff0c;行业也比较看好&#xff0c;那就选择买他们家股票&#xff0c;因为大概率他们是赢取了市场平均收益…

python接入汇率换算工具提高网站/小程序日活度

实时汇率换算工具可以帮助用户快速准确地计算不同货币之间最新的汇兑比例。无论是金融从业者或者是人们日常生活出行都会使用到&#xff0c;广泛用于国际结算、银行汇率查询应用、开展跨国贸易、投资等参考场景。 我们可以通过在网站或者小程序中接入这样一个小工具&#xff0…

【Ardiuno】实验ESP32单片机自动配置Wifi功能(图文)

这里小飞鱼按照ESP32的示例代码&#xff0c;实验一下wifi的自动配置功能。所谓的自动配置&#xff0c;就是不用提前将wifi的名称和密码写到程序里&#xff0c;这样可以保证程序在烧录上传后&#xff0c;可以通过手机端的软件来进行配置&#xff0c;可以避免反复修改代码&#x…

ChromeOS 逐渐靠近安卓

ChromeOS 逐渐 “安卓化” 谷歌在博客中透露&#xff0c;将在ChromeOS底层更广泛地使用和Android相同的技术栈。一个具体的例子是&#xff0c;ChromeOS现在已经开始使用Android的蓝牙协议栈&#xff0c;取代了之前使用的自己的协议栈。这次改变不仅提高了蓝牙配对速度&#xf…

什么是Rademacher复杂度(Rademacher Complexity)

Rademacher复杂度&#xff08;Rademacher Complexity&#xff09;是在学习理论中用于衡量函数类复杂度的一种工具&#xff0c;特别是在评估机器学习模型泛化能力时。它提供了一种量化学习算法可能过拟合数据的程度的方法。Rademacher复杂度定义了函数类在给定数据集上的随机化复…

Postman下发流表至Opendaylight

目录 任务目的 任务内容 实验原理 实验环境 实验过程 1、打开ODL控制器 2、网页端打开ODL控制页面 3、创建拓扑 4、Postman中查看交换机的信息 5、L2层流表下发 6、L3层流表下发 7、L4层流表下发 任务目的 1、掌握OpenFlow流表相关知识&#xff0c;理解SDN网络中L…

【vue-8】记事本案例

小知识点&#xff1a; 列表末尾插入数据&#xff1a; list.push("lihua") 列表删除数据&#xff1a; # index要删除数据的索引值&#xff0c;1为删除数据长度 list.splice(index,1) 完整示例代码&#xff1a; <!DOCTYPE html> <html lang"en&quo…

Oracle数据库查询常用语句

Oracle数据库查询常用语句 文章目录 Oracle数据库查询常用语句一、时间查询1、查询当天得数据 二、 一、时间查询 1、查询当天得数据 1、字段名为PLAN_DAY&#xff0c;字段类型为DATE 使用SYSDATE函数来获取当前日期&#xff0c;并且使用比较运算符来过滤出当天的记录。Oracle…