采用QSharedMemory实现多进程间的通信 Linux | window
直接上代码:简单的很
1 ///////////////////////////////////////////////////////////////////// 2 /// file: ProcessCommunicate.h 3 /// Description:本文采用<QSharedMemory>实现同一台电脑上多个进程间的通信。使用极其的简单,你只需要调用一个无参数函数就能完成。 4 /// 5 /// Copyright: 成都中科希奥科技有限公司 Official Website:https://siotech.net/ 6 /// Author: 张洪铭-小熊博(zhm-xxbs) Email:zhm_xxbs@163.com 7 /// Date: 2022-05-17 8 /// 9 ///////////////////////////////////////////////////////////////////// 10 /* 使用样例(伪代码):////////////////////////////////////////////////// 11 * ... 12 * 配置4个全局变量的初始值(非常简单),搜索:Lable:[Change] 13 * ... 14 * std::deque<DisplayMessage>::sendDisplayMsg //把需要发送的消息压入队列 15 * 16 * updateMessageDeque(); //仅仅调用这一个函数 17 * 18 * std::deque<DisplayMessage>::recvDisplayMsg //从接收消息队列中取出消息来使用 19 * ... 20 * 完整样例代码,有界面可直观操作来体验:请联系作者。 21 ///////////////////////////////////////////////////////////////////*/ 22 23 #ifndef BASE_COMMON_H 24 #define BASE_COMMON_H 25 26 #include <bit> 27 #include <map> 28 #include <string> 29 #include <assert.h> 30 #include <memory> 31 #include <deque> 32 #include <set> 33 #include <tuple> 34 #include <list> 35 #include <iostream> 36 37 #include <QSharedMemory> 38 39 ///////////////////////////////////////////////////////////////////// 40 /// 进程ID + 进程名称 + 管理者ID + 管理者属性 41 /* 42 *宏定义进程的名称 43 */ 44 #define ProcessOne ("ProcessOne(as manager)") 45 #define ProcessTwo ("ProcessTwo ") 46 #define ProcessThree ("ProcessThree") 47 48 /* 49 * variable: Id_ProcessName 50 * desc: 所有伙伴进程的ID编号和进程名称的对应关系映射 51 * Lable:[Change] 52 */ 53 extern std::map<unsigned char, std::string> ID_ProcessName; 54 55 /* 56 * variable: ID_Ower 57 * desc: 进程自己的ID编号 58 * Lable:[Change] 59 */ 60 static constexpr unsigned char ID_Owner = 0; 61 62 /* 63 * variable: ID_Manager 64 * desc: 管理者的进程编号 65 * Lable:[Change] 66 */ 67 static constexpr unsigned char ID_Manager = 0; 68 69 /* 70 * variable: Is_Manager 71 * desc: 进程自己是不是管理着进程 72 * tips: 73 * 1.当一个伙伴群体中,只安排一个管理者; 74 * 2.ture:管理者; false:伙伴; 75 * Lable:[Change] 76 */ 77 static constexpr bool Is_Manager = true; 78 79 ///////////////////////////////////////////////////////////////////// 80 /// 公用的常量值 81 /* 82 * variable: SharedMemoryReadWriteCycle 83 * desc: 每个进程读写共享内存的周期。 单位:毫秒; 84 */ 85 constexpr unsigned SharedMemoryReadWriteCycle = 500;//200; 86 87 /* 88 * variable: HeartBeatReportCycle 89 * desc: 每个进程上报自己心跳的周期。 单位:毫秒; 90 */ 91 constexpr unsigned HeartBeatReportCycle = 5*1000; 92 93 /* 94 * variable: JudgePartnerOfflineMaxCount 95 * desc: 判断伙伴进程已经离线,未读取到伙伴消息的最大次数计数值。 96 * Tips: 97 * 1. 当计数值达到 JudgePartnerOfflineMaxCount 时,认为伙伴进程已离线; 98 * 2. 读取消息的周期是 SharedMemoryReadWriteCycle, 因此要确保此值是合理的。 99 */ 100 constexpr unsigned char JudgePartnerOfflineMaxCount =\ 101 (HeartBeatReportCycle/SharedMemoryReadWriteCycle)*3; //3次本该收到心跳,但未收到,则认为离线 102 103 /* 104 * enum : MsgType 105 * desc : 枚举所有的消息类型 106 * 107 * MsgType_Invalid:非法消息; 108 * MsgType_Display:显示消息; 109 * MsgType_Control:控制消息; 110 */ 111 enum MsgType{MsgType_Invalid = 0, MsgType_Display, MsgType_Control}; 112 113 /* 114 * enum : SendType 115 * desc : 枚举所有的发送类型 116 * 117 * SendType_Invalid:非法消息; 118 * SendType_PointToPoint:点对点; 119 * SendType_Broadcast:广播; 120 * 121 * Tips: 目前只有“心跳”属于广播, 其他均为“点对点”; 122 */ 123 enum SendType{SendType_Invalid = 0, SendType_PointToPoint, SendType_Broadcast}; 124 125 /* 126 * enum : ControlMsgType 127 * desc : 枚举所有的控制消息的类型 128 * 129 * [0-100]为心跳消息,代表发送心跳进程的ID 130 * ControlMsgType_Invalid:非法控制消息; 131 * ControlMsgType_Bell:响铃; 132 * ControlMsgType_Exit:退出程序; 133 */ 134 enum ControlMsgType{/*[0-100]*/ControlMsgType_Invalid = 101, ControlMsgType_Bell, ControlMsgType_Exit}; 135 /* 136 * variable: ProcessCommunicationSharedMemory 137 * desc: 伙伴进程间通信使用的共享内存的名称 138 */ 139 constexpr char ProcessCommunicationSharedMemory[] = "ProcessCommunicationSharedMemory"; 140 141 /* 142 * variable: NonMessage 143 * desc: 共享内存中没有消息内容项; 144 */ 145 constexpr unsigned short NonMessage = -1; 146 147 /* 148 * variable: MessageMaxJumpNumber 149 * desc: 消息的最大活跃跳数; 150 * tips: 消息的跳数仅由管理者维护; 151 */ 152 constexpr unsigned char MessageMaxJumpNumber = 20; 153 154 /* 155 * variable: HeartbeatMessage 156 * desc: 心跳消息; 157 * tips: 心跳消息作为显示消息的一种; 158 */ 159 constexpr char HeartbeatMessage[] = "I'm alive"; 160 161 ///////////////////////////////////////////////////////////////////// 162 /// 每一个通信的内容格式 163 /* 164 * struct: CommunicateProtocol 165 * desc:伙伴进程间通信的协议格式; 166 * Tips: 167 * 1.毕竟采用珍贵的内存资源,因此协议体能小尽可能的小; 168 * 2.消息内容只发送一种,那就是与消息类型匹配的那一种; 169 * 3.msgJumpNum 消息存活的跳数由消息发送者指定,由管理者维护; 170 * 一般来说,点对点类型的消息,跳数为1; 171 */ 172 typedef struct _Process_Communication_Protocol{ 173 unsigned msgLen = 0; //消息长度,根据消息类型显示消息和控制消息仅包含一种,用作取消息;包括自身长度; 174 unsigned char sendType = SendType_Invalid; //消息发送发是否是管理者 175 unsigned char senderId = 0; //消息发送者的ID 0:非法ID; 其他值合法; 176 unsigned char receiverId = 0; //消息接收者的ID 0:非法ID; 其他值合法; 177 unsigned char msgType = MsgType_Invalid; //消息类型; 178 unsigned char msgJumpNum = MessageMaxJumpNumber; //消息的存活跳数; 179 std::string displayMsg; //显示消息内容; 180 unsigned char controlMsg = ControlMsgType_Invalid; //控制消息内容 181 182 std::shared_ptr<char> protocol(); 183 static std::shared_ptr<_Process_Communication_Protocol> structFromProtocol(char* protocol); 184 bool isValid(){return (wholeSize() == msgLen);} 185 unsigned wholeSize(); 186 }ProcessCommProtocol; 187 188 189 ///////////////////////////////////////////////////////////////////// 190 /// 收发的消息队列 191 /// 1. 整个伙伴群成员,分为一个管理者和多个员工。 所有员工的消息都直接汇总到管理着, 员工只接收从管理着发来的消息。 192 /// 2. 进程 “ProcessOne ” 充当管理者, 进程“ProcessTwo” 和 “ProcessThree” 充当员工。 193 /// 3. 收到某伙伴消息,则认为伙伴活着的;超过 n 次未收到某伙伴的消息,则认为已经离线,并始终未 n,不在递增; 194 /// 4. 接收队列里的进程ID都是发送者的ID,接收者默认是自己; 195 /// 5. 发送队列里的进程ID都是接收者的ID,发送者默认是自己; 196 197 /* 198 * classType:DisplayMessage 199 * desc: 显示消息元组 200 * 201 * get<0>(DisplayMessage):进程ID 202 * get<1>(DisplayMessage):消息内容 203 */ 204 typedef std::tuple<unsigned char, std::string> DisplayMessage; 205 206 /* 207 * classType:ControlMessage 208 * desc: 控制消息元组 209 * 210 * get<0>(ControlMessage):进程ID 211 * get<1>(ControlMessage):消息内容 212 */ 213 typedef std::tuple<unsigned char, unsigned char> ControlMessage; 214 215 extern std::deque<DisplayMessage> recvDisplayMsg; //收到的伙伴(员工)的消息队列; 216 extern std::deque<ControlMessage> recvControlMsg; 217 extern std::deque<DisplayMessage> sendDisplayMsg; //需要发送给伙伴(员工)的消息队列; 218 extern std::deque<ControlMessage> sendControlMsg; 219 extern std::set<unsigned char> alivePartner; //“活着的”伙伴进程ID 220 extern std::map<unsigned char, unsigned char> partnerOffline; //伙伴离线计数 <ID, Count> 221 222 ///////////////////////////////////////////////////////////////////// 223 /// 对共享内存的读和写 224 /// 225 /// 共享内存里存放消息的协议为:消息数量+消息1+消息2+...+消息n; 226 /// 消息数量:unsigned short 两字节; 指定为最大值时为无消息内容(当然0也是无消息内容); 227 /// 消息n: ProcessCommProtocol 结构体内容; 228 /// 229 /* 230 * variable: sharedMemoryBuf 231 * desc: 共享内存的地址 232 * tips: 读写操作前,先对 sharedMemoryBuf 赋值; 读写操作后,再对 sharedMemoryBuf 重置; 233 */ 234 extern char * sharedMemoryBuf; 235 236 /* 237 * variable: currentSharedMemorySize 238 * desc: 当前共享内存的大小 239 */ 240 extern size_t currentSharedMemorySize; 241 242 /* 243 * func: updateMessageDeque 244 * desc: 刷新消息队列。 从消息队列中读取;& 维护消息队列; & 把消息写入到队列中; 245 * Tips: 调用一次,就完成一次所有消息的读取,所有消息的写入; 246 */ 247 extern void updateMessageDeque(); 248 249 ///////////////////////////////////////////////////////////////////// 250 /// 共享内存QSharedMemory 251 static QSharedMemory sharedMemory(ProcessCommunicationSharedMemory); 252 #endif //BASE_COMMON_H
.cpp
1 #include "ProcessCommunicate.h" 2 3 /* 4 * variable: Id_ProcessName 5 * desc: 所有伙伴进程的ID编号和进程名称的对应关系映射 6 * Lable:[Change] 7 */ 8 std::map<unsigned char, std::string> ID_ProcessName = \ 9 {\ 10 {0, ProcessOne}, {1, ProcessTwo},{2, ProcessThree} 11 }; 12 13 14 ///////////////////////////////////////////////////////////////////// 15 /// 对共享内存的读和写 16 /// 17 /// 共享内存里存放消息的协议为:消息数量+消息1+消息2+...+消息n; 18 /// 消息数量:unsigned short 两字节; 指定为最大值时为无消息内容(当然0也是无消息内容); 19 /// 消息n: ProcessCommProtocol 结构体内容; 20 /// 21 22 /* 23 * variable: sharedMemoryBuf 24 * desc: 共享内存的地址 25 * tips: 读写操作前,先对 sharedMemoryBuf 赋值; 读写操作后,再对 sharedMemoryBuf 重置; 26 */ 27 char * sharedMemoryBuf = nullptr; 28 29 30 /* 31 * variable: currentSharedMemorySize 32 * desc: 当前共享内存的大小 33 */ 34 size_t currentSharedMemorySize = 0; 35 36 /* 37 * variable: messageList 38 * desc: 消息内容项的链表 39 * tips: 40 * 读取(read)共享内存时,同时记录下每一个消息内容项到链表里管理起来, 41 * 以便重新整理(recoginze)和写(write)消息时使用。 42 */ 43 std::list<std::shared_ptr<ProcessCommProtocol> > messageList; 44 45 /* 46 * struct: SharedMemoryGuard 47 * desc: 守护 sharedMemoryBuf 使用后一定会得到重置; 48 */ 49 struct SharedMemoryBufGuard{ 50 SharedMemoryBufGuard(){ 51 messageList.clear(); 52 } 53 ~SharedMemoryBufGuard(){ 54 sharedMemoryBuf = nullptr; 55 messageList.clear(); 56 } 57 }; 58 59 60 /* 61 * func:readMessageFromSharedMemory 62 * desc:读取消息内容, 一次性全部读取; & 维护伙伴计数(partnerOffline); & 更新“活着的”伙伴(alivePartner); 63 * tips: 64 * 1.伙伴进程(员工)只读取来自管理者的消息; 65 * 2.管理者进程读取所有来自伙伴进程的消息;不读取来自管理者的消息; 66 * 调用关系: readMessageFromSharedMemory() + reorganizeSharedMemory() + writeMessageToSharedMemory() 67 * 3. 内部调用 68 */ 69 void readMessageFromSharedMemory() 70 { 71 if (!sharedMemoryBuf){ 72 return ; 73 } 74 75 unsigned short offset = 0; //计算偏移 76 77 //读取:共享内存协议 78 unsigned short msgCount = 0; //消息内容项的数量; -1:没有消息内容项; 79 memcpy((char*)&msgCount, sharedMemoryBuf+offset, sizeof(msgCount)); 80 offset += sizeof(msgCount); 81 82 for (; msgCount != NonMessage && msgCount-- > 0;)//循环处理每一个消息内容项 83 { 84 85 std::shared_ptr<ProcessCommProtocol> aMessage(\ 86 ProcessCommProtocol::structFromProtocol(\ 87 sharedMemoryBuf+offset)); 88 89 offset += aMessage->wholeSize(); 90 91 if (!aMessage){ 92 continue; 93 } 94 95 //不管是不是自己需要接收的消息,都需要连接到消息链表中,用于重新整理链表使用; 96 messageList.push_back(aMessage); 97 98 ///start:在取出具体的消息内容之前,先判断该消息是否是当前进程需要的 99 //伙伴进程(普通)只接收来自管理者的消息;伙伴间的消息,必须汇总到管理者处,再由管理者派发,包括心跳; 100 if(!Is_Manager && ID_Manager != aMessage->senderId){ 101 continue; 102 } 103 104 //进程自己不接收自己发出的消息 105 if (ID_Owner == aMessage->senderId){ 106 continue; 107 } 108 109 //进程只接收发给自己的消息,不是自己的不收 110 if (ID_Owner != aMessage->receiverId){ 111 continue; 112 } 113 ///end: 114 115 ///start: 如何处理收到的消息? 116 //1. 仅仅需要把收到的消息分类放入消息队列即可 117 if (MsgType_Control == aMessage->msgType && ControlMsgType_Invalid != aMessage->controlMsg){ 118 recvControlMsg.push_back(ControlMessage(aMessage->senderId, aMessage->controlMsg)); 119 } 120 else if (MsgType_Display == aMessage->msgType){ 121 recvDisplayMsg.push_back(DisplayMessage(aMessage->senderId, aMessage->displayMsg)); 122 } 123 else{ 124 //非法消息 125 } 126 ///end: 127 } 128 129 } 130 131 /* 132 * struct: IteratorPlusGuard 133 * desc: 迭代器自动增加守卫 134 */ 135 template<typename T> 136 struct IteratorPlusGuard{ 137 IteratorPlusGuard(T& t):_t(t){} 138 ~IteratorPlusGuard(){ 139 ++_t; 140 } 141 T& _t; 142 }; 143 144 /* 145 * func:reorganizeSharedMemory 146 * desc:重新整理共享内存。原则,尽量减轻伙伴进程的负担。 147 * tips: 148 * 1. 管理者进程,整理消息内容; 149 * 2. 管理者进程,删除不再使用的消息; & 把伙伴进程发送给伙伴进程的消息,重定向为由管理者发送给伙伴进程的消息; 150 * 3. 管理者和伙伴进程,删除发送者是管理者,接收者是自己,且不是广播(心跳)的消息; 151 * 4. 管理者和伙伴进程,维护伙伴计数(partnerOffline); & 更新“活着的”伙伴(alivePartner); 152 * 5. 内部调用 153 */ 154 void reorganizeSharedMemory() 155 { 156 if (!sharedMemoryBuf){ 157 return ; 158 } 159 160 //维护每一个伙伴进程是否存活 161 for (auto iterator = partnerOffline.begin(); iterator != partnerOffline.end(); ++iterator){ 162 partnerOffline[iterator->first] += 1;//默认每一次加1 163 } 164 165 //遍历每一个消息内容项 166 auto iterator = messageList.begin(); 167 while(iterator != messageList.end()){ 168 auto aMessage = *iterator; 169 170 ///start: 维护伙伴进程是否存活,只要发送者出现一次某伙伴,就代表该伙伴儿活着的 171 partnerOffline[aMessage->senderId] = 0; //0:离线次数为0, 伙伴活着的; 172 173 if (Is_Manager){ 174 //管理者需要把伙伴上报的心跳包打散并分发 175 //但不用分发管理者的心跳包,因为每一种包都是由管理者发出的,已经可以体现出管理者的心跳 176 if (ID_Manager != aMessage->senderId && SendType_Broadcast == aMessage->sendType){ 177 for (auto partner : alivePartner){ 178 if (ID_Manager == partner /*|| partner == aMessage->senderId*/){ 179 //不用再次发给管理者 180 //需要把心跳发给发出心跳进程自己,表示管理者存在,伙伴进程才能看到心跳 181 continue; 182 } 183 sendControlMsg.push_back(ControlMessage(partner, aMessage->senderId));//打散后分发心跳 184 } 185 } 186 } 187 else{//非管理者才需要特别的解析伙伴的心跳 188 if (MsgType_Control == aMessage->msgType \ 189 && ControlMsgType_Invalid > aMessage->controlMsg){//表示上报心跳的伙伴进程的ID 190 partnerOffline[aMessage->controlMsg] = 0; //0:离线次数为0, 伙伴活着的; 191 } 192 } 193 ///end: 194 195 if (Is_Manager){//管理者进程-删除不合法,或不再需要的消息 196 ///start: 消息的类型不合法,则消息不再继续传递 197 if (MsgType_Invalid == aMessage->msgType){ 198 iterator = messageList.erase(iterator); 199 continue; 200 } 201 ///end: 202 203 ///start: 消息的发送类型不合法,则消息不再继续传递 204 if (SendType_Invalid == aMessage->sendType){ 205 iterator = messageList.erase(iterator); 206 continue; 207 } 208 ///end: 209 210 ///start: 消息是控制消息,但控制消息的具体内容不合法 211 if (MsgType_Control == aMessage->msgType && ControlMsgType_Invalid == aMessage->controlMsg){ 212 iterator = messageList.erase(iterator); 213 continue; 214 } 215 ///end: 216 217 ///start: 消息的接收者为管理者,则消息不再继续传递; 218 if (ID_Manager == aMessage->receiverId){ 219 iterator = messageList.erase(iterator); 220 continue; 221 } 222 ///end: 223 224 ///start: 屏蔽伙伴进程自己给自己发消息; 225 if (ID_Manager != aMessage->senderId \ 226 && aMessage->senderId == aMessage->receiverId){ 227 iterator = messageList.erase(iterator); 228 continue; 229 } 230 ///end: 231 232 ///start: 维护消息内容项的存活跳数 233 //及时删除无用的消息。例如:某伙伴在未收到消息的时候退出了。 234 //并且需要反向写入到共享内存中,在 writeMessageToSharedMemory 完成 235 if (ID_Manager == aMessage->senderId){ 236 --aMessage->msgJumpNum; 237 } 238 else{ 239 //伙伴发给伙伴的消息,等管理者重定向之后再维护跳数 240 } 241 //如果消息内容项的跳数减少为0,则把该条消息内容项删掉 242 if (0 == aMessage->msgJumpNum){ 243 iterator = messageList.erase(iterator); 244 continue; 245 } 246 ///end: 247 }//if (Is_Manager) 248 249 ///start: 管理者和伙伴进程都不再需要由管理者发给自己的消息 250 //及时删除作废的消息, 人人有责 251 if (ID_Manager == aMessage->senderId && ID_Owner == aMessage->receiverId) 252 { 253 iterator = messageList.erase(iterator); 254 continue; 255 } 256 ///end: 257 258 IteratorPlusGuard<decltype (messageList.begin()) > itGuard(iterator); 259 260 if (Is_Manager){//管理者改写消息,例如:伙伴发给伙伴的; 261 262 ///start: 把伙伴进程发送给伙伴进程的消息,重定向为由管理者发送给伙伴进程的消息 263 if (ID_Manager != aMessage->senderId && ID_Manager != aMessage->receiverId){ 264 aMessage->sendType = SendType_PointToPoint; 265 aMessage->senderId = ID_Manager; 266 aMessage->msgJumpNum = 1; 267 continue; 268 } 269 ///end: 270 } 271 272 }//while(iterator != messageList.end()) 273 274 //维护活着的伙伴儿 275 alivePartner.clear(); 276 for (auto iterator = partnerOffline.begin(); iterator != partnerOffline.end(); ++iterator){ 277 if (partnerOffline[iterator->first] < JudgePartnerOfflineMaxCount){ 278 alivePartner.insert(iterator->first); 279 } 280 } 281 } 282 283 /* 284 * func:writeMessageToSharedMemory 285 * desc:写消息内容, 一次性全部写入; 286 * tips: 287 * 1. 伙伴进程(员工)追加写入;管理者追加写入; 288 * 2. 内部调用 289 * 290 */ 291 void writeMessageToSharedMemory() 292 { 293 if (!sharedMemoryBuf){ 294 return ; 295 } 296 297 //普通消息; 298 for (auto msg : sendDisplayMsg){ 299 std::shared_ptr<ProcessCommProtocol> aMessage(new ProcessCommProtocol); 300 //aMessage->msgLen; 301 aMessage->displayMsg = std::get<1>(msg); 302 aMessage->sendType = (HeartbeatMessage == aMessage->displayMsg)?\ 303 SendType_Broadcast:SendType_PointToPoint; 304 aMessage->senderId = ID_Owner; 305 aMessage->receiverId = std::get<0>(msg); 306 aMessage->msgType = MsgType_Display; 307 aMessage->msgJumpNum = 1; //点对点跳数1就够了。广播会在管理者收到广播后转换成点对点散出去。 308 309 //aMessage->displayMsg; 310 //aMessage->controlMsg 对于显示消息,控制消息默认非法 311 312 aMessage->msgLen = aMessage->wholeSize(); 313 messageList.push_back(aMessage); 314 } 315 sendDisplayMsg.clear(); 316 317 //控制消息: 318 for (auto msg : sendControlMsg){ 319 std::shared_ptr<ProcessCommProtocol> aMessage(new ProcessCommProtocol); 320 //aMessage->msgLen; 321 aMessage->sendType = SendType_PointToPoint; 322 aMessage->senderId = ID_Owner; 323 aMessage->receiverId = std::get<0>(msg); 324 aMessage->msgType = MsgType_Control; 325 aMessage->msgJumpNum = 1; //点对点跳数1就够了。 326 327 //aMessage->displayMsg; 对于控制消息,显示消息默认为空 328 aMessage->controlMsg = std::get<1>(msg); 329 aMessage->msgLen = aMessage->wholeSize(); 330 messageList.push_back(aMessage); 331 } 332 sendControlMsg.clear(); 333 334 ///start: 写入共享内存之前,先把共享内存重置 335 memset(sharedMemoryBuf, 0, currentSharedMemorySize); 336 ///end: 337 338 ///start: 写入共享内存 339 size_t offset = 0; 340 unsigned short msgCount = messageList.size(); 341 memcpy(sharedMemoryBuf + offset, (char*)&msgCount, sizeof(msgCount)); 342 offset += sizeof(msgCount); 343 344 for (auto aMessage : messageList){ 345 auto protocol = aMessage->protocol(); 346 if (!protocol){ 347 continue; 348 } 349 memcpy(sharedMemoryBuf + offset, protocol.get(), aMessage->wholeSize()); 350 offset += aMessage->wholeSize(); 351 } 352 ///end: 353 } 354 355 356 ///////////////////////////////////////////////////////////////////// 357 /// 收发的消息队列 358 /// 1. 整个伙伴群成员,分为一个管理者和多个员工。 所有员工的消息都直接汇总到管理着, 员工只接收从管理着发来的消息。 359 /// 2. 进程 “ProcessOne ” 充当管理者, 进程“ProcessTwo” 和 “ProcessThree” 充当员工。 360 /// 3. 收到某伙伴消息,则认为伙伴活着的;超过 n 次未收到某伙伴的消息,则认为已经离线,并始终未 n,不在递增; 361 /// 4. 接收队列里的进程ID(消息接收者)都是自己; 362 /// 5. 发送队列里的进程ID(消息接收者)都是目标; 363 std::deque<DisplayMessage> recvDisplayMsg; //收到的伙伴(员工)的消息队列; 364 std::deque<ControlMessage> recvControlMsg; 365 std::deque<DisplayMessage> sendDisplayMsg; //需要发送给伙伴(员工)的消息队列; 366 std::deque<ControlMessage> sendControlMsg; 367 std::set<unsigned char> alivePartner; //“活着的”伙伴进程ID 368 std::map<unsigned char, unsigned char> partnerOffline; //伙伴离线计数 <ID, Count> 369 370 371 ///////////////////////////////////////////////////////////////////// 372 /// 每一个通信的内容格式 373 std::shared_ptr<char> _Process_Communication_Protocol::protocol(){ 374 if (!isValid()){ 375 return nullptr; 376 } 377 378 std::shared_ptr<char> buf(new char[wholeSize()+1]); 379 unsigned offset = 0; 380 381 ///这里不要用 memset() 对 buf 做初始化,0值对于某个协议成员来说是有意义的; 382 ///整个buf都会满满的填充上协议内容,没有多余的; 383 384 //消息长度 385 memcpy(buf.get() + offset, (char*)&msgLen, sizeof(msgLen)); 386 offset += sizeof(msgLen); 387 388 //消息发送发是否是管理者 389 memcpy(buf.get() + offset, (char*)&sendType, sizeof(sendType)); 390 offset += sizeof(sendType); 391 392 //消息发送者的ID 393 memcpy(buf.get() + offset, (char*)&senderId, sizeof(senderId)); 394 offset += sizeof(senderId); 395 396 //消息接收者的ID 397 memcpy(buf.get() + offset, (char*)&receiverId, sizeof(receiverId)); 398 offset += sizeof(receiverId); 399 400 //消息类型 401 memcpy(buf.get() + offset, (char*)&msgType, sizeof(msgType)); 402 offset += sizeof(msgType); 403 404 //消息的存活跳数 405 memcpy(buf.get() + offset, (char*)&msgJumpNum, sizeof(msgJumpNum)); 406 offset += sizeof(msgJumpNum); 407 408 //消息内容 409 if (MsgType_Display == msgType){ 410 memcpy(buf.get() + offset, displayMsg.c_str(), displayMsg.length()); 411 offset += displayMsg.length(); 412 } 413 else if (MsgType_Control == msgType){ 414 memcpy(buf.get() + offset, (char*)&controlMsg, sizeof(controlMsg)); 415 offset += sizeof(controlMsg); 416 } 417 else{ 418 return nullptr; 419 } 420 (void)offset; 421 return buf; 422 } 423 424 std::shared_ptr<_Process_Communication_Protocol> _Process_Communication_Protocol::structFromProtocol(char *protocol){ 425 if (!protocol){ 426 return nullptr; 427 } 428 std::shared_ptr<_Process_Communication_Protocol> aMessage(new _Process_Communication_Protocol); 429 unsigned offset = 0; 430 memcpy((char*)&aMessage->msgLen, protocol+ offset, sizeof(aMessage->msgLen)); 431 offset += sizeof(aMessage->msgLen); 432 433 memcpy((char*)&aMessage->sendType,protocol+ offset, sizeof(aMessage->sendType)); 434 offset += sizeof(aMessage->sendType); 435 436 memcpy((char*)&aMessage->senderId,protocol+ offset, sizeof(aMessage->senderId)); 437 offset += sizeof(aMessage->senderId); 438 439 memcpy((char*)&aMessage->receiverId,protocol+ offset, sizeof(aMessage->receiverId)); 440 offset += sizeof(aMessage->receiverId); 441 442 memcpy((char*)&aMessage->msgType,protocol+ offset, sizeof(aMessage->msgType)); 443 offset += sizeof(aMessage->msgType); 444 445 memcpy((char*)&aMessage->msgJumpNum,protocol+ offset, sizeof(aMessage->msgJumpNum)); 446 offset += sizeof(aMessage->msgJumpNum); 447 448 if (MsgType_Display == aMessage->msgType){ 449 450 unsigned char fixedLen = 0; 451 fixedLen += sizeof(aMessage->msgLen); 452 fixedLen += sizeof(aMessage->sendType); 453 fixedLen += sizeof(aMessage->senderId); 454 fixedLen += sizeof(aMessage->receiverId); 455 fixedLen += sizeof(aMessage->msgType); 456 fixedLen += sizeof(aMessage->msgJumpNum); 457 458 std::shared_ptr<char> msg(new char[(aMessage->msgLen - fixedLen) +1]); 459 memset(msg.get(), 0, (aMessage->msgLen - fixedLen) +1); 460 memcpy(msg.get(),protocol+ offset, aMessage->msgLen - fixedLen); 461 aMessage->displayMsg = std::string(msg.get()); 462 offset += (aMessage->msgLen - fixedLen); 463 } 464 else if (MsgType_Control == aMessage->msgType){ 465 memcpy((char*)&aMessage->controlMsg,protocol+ offset, sizeof(aMessage->controlMsg)); 466 offset += sizeof(aMessage->controlMsg); 467 } 468 else{ 469 return nullptr; 470 } 471 (void)offset; 472 return aMessage; 473 } 474 475 unsigned _Process_Communication_Protocol::wholeSize(){ 476 unsigned size = 0; 477 if (MsgType_Display == msgType){ 478 size = displayMsg.length(); 479 } 480 else if (MsgType_Control == msgType){ 481 size = sizeof(controlMsg); 482 } 483 else{ 484 return 0; 485 } 486 487 return (size\ 488 + sizeof(msgLen)\ 489 + sizeof(sendType)\ 490 + sizeof(senderId)\ 491 + sizeof(receiverId)\ 492 + sizeof(msgType)\ 493 + sizeof(msgJumpNum)); 494 } 495 496 497 ///////////////////////////////////////////////////////////////////// 498 /// 共享内存QSharedMemory 499 /* 500 * struct: SharedMemoryGuard 501 * desc: 守护 m_sharedMemory 使用前一定 lock(), 并赋值给 sharedMemoryBuf;使用后一定 unlock; 502 */ 503 struct SharedMemoryGuard{ 504 SharedMemoryGuard(){ 505 if (Is_Manager){ 506 if (!sharedMemory.isAttached()){ 507 if(!sharedMemory.create(1024)){ 508 //qDebug("create shared memory segment failed."); 509 sharedMemory.attach(); 510 } 511 else{ 512 //qDebug("create shared memory segment successed."); 513 } 514 } 515 else{ 516 //qDebug("already create shared memory segment."); 517 } 518 } 519 else{ 520 if (sharedMemory.attach()){ 521 //qDebug("shared memory attach successed."); 522 } 523 else{ 524 //qDebug("shared memory attach failed."); 525 } 526 } 527 528 if (sharedMemory.isAttached()){ 529 sharedMemory.lock(); 530 sharedMemoryBuf = (char*)sharedMemory.data(); 531 currentSharedMemorySize = sharedMemory.size(); 532 } 533 else { 534 sharedMemoryBuf = nullptr; 535 currentSharedMemorySize = 0; 536 } 537 } 538 ~SharedMemoryGuard(){ 539 if (sharedMemory.isAttached()){ 540 sharedMemory.unlock(); 541 } 542 } 543 }; 544 545 /* 546 * func: updateMessageDeque 547 * desc: 刷新消息队列。 从消息队列中读取;& 维护消息队列; & 把消息写入到队列中; 548 * Tips: 调用一次,就完成一次所有消息的读取,所有消息的写入; 549 */ 550 void updateMessageDeque() 551 { 552 SharedMemoryGuard guard; 553 SharedMemoryBufGuard bufGuard; 554 readMessageFromSharedMemory(); 555 reorganizeSharedMemory(); 556 writeMessageToSharedMemory(); 557 }