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…

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; 嵌入式分析是指能够将数据分析的特性和功…

用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.逾期订单…

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…

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…

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…

R语言ggHoriPlot包绘制地平线图

数据和代码获取&#xff1a;请查看主页个人信息&#xff01;&#xff01;&#xff01; 关键词“地平线图” 1. 数据读取与处理 首先&#xff0c;从TSV文件中读取数据&#xff0c;并进行数据清洗和处理。 rm(listls()) pacman::p_load(tidyverse,ggalt,ggHoriPlot,hrbrthemes…

教程:A5000 GPU 上运行阿里最新开源大模型 Qwen2

这是我们新一篇关于大模型的文章&#xff0c;我们此前还讲过如何运行 LLama3 大模型。而这次&#xff0c;我们将使用 Ollama 运行阿里千问Qwen2:7b。要知道 Qwen2 可是目前最热门的开源大语言模型了&#xff0c;甚至在一些性能测试中比 LLama3 表现还突出。谁不想试试看呢&…

C#下WinForm多语种切换

这是应一个网友要求写的&#xff0c;希望对你有所帮助。本文将介绍如何在一个WinForm应用程序中实现多语种切换。通过一个简单的示例&#xff0c;你将了解到如何使用资源文件管理不同语言的文本&#xff0c;并通过用户界面实现语言切换。 创建WinForm项目 打开Visual Studio&a…

最新下载:XmanagerXShell【软件附加安装教程】

​XManager企业版是一款完整的企业网络连接套件&#xff0c;它配备了一个高性能的PC服务器&#xff0c;安全终端模拟器&#xff0c;是一个一体化的解决方案&#xff0c;将xmanager&#xff0c;xshell&#xff0c;xftp&#xff0c;xlpd&#xff0c;Xbrowser及xstart放置在一个软…

C#发送邮件

C#发送邮件代码&#xff0c;亲测可用。 using System; using System.Net; using System.Net.Mail;namespace MailSend {class Program{static void Main(string[] args){try{MailAddress receiver new MailAddress("666666666qq.com");//666666666qq.com 换成收件人…

从零开始手把手Vue3+TypeScript+ElementPlus管理后台项目实战十(整体布局03之界面美化)

删除style.css 删除style.css(和main.ts同级) 并且注释掉main.ts中对style.css的导入。 修改App.vue 添加样式设置高度100% 安装sass pnpm install -D sass修改PageSidebar.vue 修改index.vue 修改src/layout/index.vue src/layout/index.vue添加样式 <style lang&quo…