├── .gitattributes ├── .gitignore ├── LICENSE ├── MessageQueue ├── .vscode │ └── settings.json ├── LICENSE ├── MqClient │ ├── admin.hpp │ ├── channel.hpp │ ├── client │ ├── client.cc │ ├── connection.hpp │ ├── consume_client.cc │ ├── consumer.hpp │ ├── data │ │ └── admin │ │ │ ├── binding.txt │ │ │ ├── exchange.txt │ │ │ ├── info.txt │ │ │ └── queue.txt │ ├── load.hpp │ ├── makefile │ └── worker.hpp ├── MqCommon │ ├── admin.pb.cc │ ├── admin.pb.h │ ├── admin.proto │ ├── color.hpp │ ├── helper.hpp │ ├── logger.hpp │ ├── msg.pb.cc │ ├── msg.pb.h │ ├── msg.proto │ ├── proto.pb.cc │ ├── proto.pb.h │ ├── proto.proto │ ├── threadpool.hpp │ ├── user.pb.cc │ ├── user.pb.h │ └── user.proto ├── MqServer │ ├── binding.hpp │ ├── broker.hpp │ ├── channel.hpp │ ├── connection.hpp │ ├── consumer.hpp │ ├── data │ │ └── meta.db │ ├── exchange.hpp │ ├── host.hpp │ ├── makefile │ ├── message.hpp │ ├── queue.hpp │ ├── route.hpp │ ├── server │ ├── server.cc │ └── users.hpp └── MqThird │ └── include │ ├── codec.cc │ ├── codec.h │ ├── dispatcher.h │ └── google-inl.h ├── README.md └── image ├── 1.png ├── client.gif ├── image-20241224232027606.png ├── image-20241224232242443.png ├── image-20241224232429831.png ├── image-20241224232544644.png ├── image-20241224232705876.png ├── image-20241224232711477.png ├── image-20241224232849081.png ├── image-20241224232919773.png ├── image-20241224232924486.png ├── image-20241224233313372.png ├── image-20241224233331337.png ├── image-20241224233514017.png ├── image-20241224233522934.png ├── image-20241224233540443.png ├── image-20241224233846104.png ├── image-20241224233850735.png ├── image-20241224233855070.png ├── server.gif └── 图片1.png /.gitattributes: -------------------------------------------------------------------------------- 1 | *.a filter=lfs diff=lfs merge=lfs -text 2 | *.so filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 木兰宽松许可证,第2版 2 | 3 | 木兰宽松许可证,第2版 4 | 5 | 2020年1月 http://license.coscl.org.cn/MulanPSL2 6 | 7 | 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 8 | 9 | 0. 定义 10 | 11 | “软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 12 | 13 | “贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 14 | 15 | “贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 16 | 17 | “法人实体” 是指提交贡献的机构及其“关联实体”。 18 | 19 | “关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是 20 | 指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 21 | 22 | 1. 授予版权许可 23 | 24 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可 25 | 以复制、使用、修改、分发其“贡献”,不论修改与否。 26 | 27 | 2. 授予专利许可 28 | 29 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定 30 | 撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡 31 | 献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软 32 | 件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“ 33 | 关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或 34 | 其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权 35 | 行动之日终止。 36 | 37 | 3. 无商标许可 38 | 39 | “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定 40 | 的声明义务而必须使用除外。 41 | 42 | 4. 分发限制 43 | 44 | 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“ 45 | 本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 46 | 47 | 5. 免责声明与责任限制 48 | 49 | “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对 50 | 任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于 51 | 何种法律理论,即使其曾被建议有此种损失的可能性。 52 | 53 | 6. 语言 54 | 55 | “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文 56 | 版为准。 57 | 58 | 条款结束 59 | 60 | 如何将木兰宽松许可证,第2版,应用到您的软件 61 | 62 | 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: 63 | 64 | 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; 65 | 66 | 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; 67 | 68 | 3, 请将如下声明文本放入每个源文件的头部注释中。 69 | 70 | Copyright (c) [Year] [name of copyright holder] 71 | [Software Name] is licensed under Mulan PSL v2. 72 | You can use this software according to the terms and conditions of the Mulan 73 | PSL v2. 74 | You may obtain a copy of Mulan PSL v2 at: 75 | http://license.coscl.org.cn/MulanPSL2 76 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 77 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 78 | NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 79 | See the Mulan PSL v2 for more details. 80 | 81 | Mulan Permissive Software License,Version 2 82 | 83 | Mulan Permissive Software License,Version 2 (Mulan PSL v2) 84 | 85 | January 2020 http://license.coscl.org.cn/MulanPSL2 86 | 87 | Your reproduction, use, modification and distribution of the Software shall 88 | be subject to Mulan PSL v2 (this License) with the following terms and 89 | conditions: 90 | 91 | 0. Definition 92 | 93 | Software means the program and related documents which are licensed under 94 | this License and comprise all Contribution(s). 95 | 96 | Contribution means the copyrightable work licensed by a particular 97 | Contributor under this License. 98 | 99 | Contributor means the Individual or Legal Entity who licenses its 100 | copyrightable work under this License. 101 | 102 | Legal Entity means the entity making a Contribution and all its 103 | Affiliates. 104 | 105 | Affiliates means entities that control, are controlled by, or are under 106 | common control with the acting entity under this License, ‘control’ means 107 | direct or indirect ownership of at least fifty percent (50%) of the voting 108 | power, capital or other securities of controlled or commonly controlled 109 | entity. 110 | 111 | 1. Grant of Copyright License 112 | 113 | Subject to the terms and conditions of this License, each Contributor hereby 114 | grants to you a perpetual, worldwide, royalty-free, non-exclusive, 115 | irrevocable copyright license to reproduce, use, modify, or distribute its 116 | Contribution, with modification or not. 117 | 118 | 2. Grant of Patent License 119 | 120 | Subject to the terms and conditions of this License, each Contributor hereby 121 | grants to you a perpetual, worldwide, royalty-free, non-exclusive, 122 | irrevocable (except for revocation under this Section) patent license to 123 | make, have made, use, offer for sale, sell, import or otherwise transfer its 124 | Contribution, where such patent license is only limited to the patent claims 125 | owned or controlled by such Contributor now or in future which will be 126 | necessarily infringed by its Contribution alone, or by combination of the 127 | Contribution with the Software to which the Contribution was contributed. 128 | The patent license shall not apply to any modification of the Contribution, 129 | and any other combination which includes the Contribution. If you or your 130 | Affiliates directly or indirectly institute patent litigation (including a 131 | cross claim or counterclaim in a litigation) or other patent enforcement 132 | activities against any individual or entity by alleging that the Software or 133 | any Contribution in it infringes patents, then any patent license granted to 134 | you under this License for the Software shall terminate as of the date such 135 | litigation or activity is filed or taken. 136 | 137 | 3. No Trademark License 138 | 139 | No trademark license is granted to use the trade names, trademarks, service 140 | marks, or product names of Contributor, except as required to fulfill notice 141 | requirements in section 4. 142 | 143 | 4. Distribution Restriction 144 | 145 | You may distribute the Software in any medium with or without modification, 146 | whether in source or executable forms, provided that you provide recipients 147 | with a copy of this License and retain copyright, patent, trademark and 148 | disclaimer statements in the Software. 149 | 150 | 5. Disclaimer of Warranty and Limitation of Liability 151 | 152 | THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY 153 | KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR 154 | COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT 155 | LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING 156 | FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO 157 | MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF 158 | THE POSSIBILITY OF SUCH DAMAGES. 159 | 160 | 6. Language 161 | 162 | THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION 163 | AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF 164 | DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION 165 | SHALL PREVAIL. 166 | 167 | END OF THE TERMS AND CONDITIONS 168 | 169 | How to Apply the Mulan Permissive Software License,Version 2 170 | (Mulan PSL v2) to Your Software 171 | 172 | To apply the Mulan PSL v2 to your work, for easy identification by 173 | recipients, you are suggested to complete following three steps: 174 | 175 | i. Fill in the blanks in following statement, including insert your software 176 | name, the year of the first publication of your software, and your name 177 | identified as the copyright owner; 178 | 179 | ii. Create a file named "LICENSE" which contains the whole context of this 180 | License in the first directory of your software package; 181 | 182 | iii. Attach the statement to the appropriate annotated syntax at the 183 | beginning of each source file. 184 | 185 | Copyright (c) [Year] [name of copyright holder] 186 | [Software Name] is licensed under Mulan PSL v2. 187 | You can use this software according to the terms and conditions of the Mulan 188 | PSL v2. 189 | You may obtain a copy of Mulan PSL v2 at: 190 | http://license.coscl.org.cn/MulanPSL2 191 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 192 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 193 | NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 194 | See the Mulan PSL v2 for more details. 195 | -------------------------------------------------------------------------------- /MessageQueue/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "future": "cpp", 4 | "cctype": "cpp", 5 | "clocale": "cpp", 6 | "cmath": "cpp", 7 | "csignal": "cpp", 8 | "cstdarg": "cpp", 9 | "cstddef": "cpp", 10 | "cstdio": "cpp", 11 | "cstdlib": "cpp", 12 | "cstring": "cpp", 13 | "ctime": "cpp", 14 | "cwchar": "cpp", 15 | "cwctype": "cpp", 16 | "any": "cpp", 17 | "array": "cpp", 18 | "atomic": "cpp", 19 | "strstream": "cpp", 20 | "bit": "cpp", 21 | "*.tcc": "cpp", 22 | "bitset": "cpp", 23 | "chrono": "cpp", 24 | "codecvt": "cpp", 25 | "compare": "cpp", 26 | "complex": "cpp", 27 | "concepts": "cpp", 28 | "condition_variable": "cpp", 29 | "coroutine": "cpp", 30 | "cstdint": "cpp", 31 | "deque": "cpp", 32 | "list": "cpp", 33 | "map": "cpp", 34 | "set": "cpp", 35 | "string": "cpp", 36 | "unordered_map": "cpp", 37 | "unordered_set": "cpp", 38 | "vector": "cpp", 39 | "exception": "cpp", 40 | "algorithm": "cpp", 41 | "functional": "cpp", 42 | "iterator": "cpp", 43 | "memory": "cpp", 44 | "memory_resource": "cpp", 45 | "numeric": "cpp", 46 | "optional": "cpp", 47 | "random": "cpp", 48 | "ratio": "cpp", 49 | "source_location": "cpp", 50 | "string_view": "cpp", 51 | "system_error": "cpp", 52 | "tuple": "cpp", 53 | "type_traits": "cpp", 54 | "utility": "cpp", 55 | "fstream": "cpp", 56 | "initializer_list": "cpp", 57 | "iomanip": "cpp", 58 | "iosfwd": "cpp", 59 | "iostream": "cpp", 60 | "istream": "cpp", 61 | "limits": "cpp", 62 | "mutex": "cpp", 63 | "new": "cpp", 64 | "numbers": "cpp", 65 | "ostream": "cpp", 66 | "semaphore": "cpp", 67 | "sstream": "cpp", 68 | "stdexcept": "cpp", 69 | "stop_token": "cpp", 70 | "streambuf": "cpp", 71 | "thread": "cpp", 72 | "cfenv": "cpp", 73 | "cinttypes": "cpp", 74 | "typeindex": "cpp", 75 | "typeinfo": "cpp", 76 | "variant": "cpp", 77 | "*.ipp": "cpp" 78 | } 79 | } -------------------------------------------------------------------------------- /MessageQueue/LICENSE: -------------------------------------------------------------------------------- 1 | 木兰宽松许可证,第2版 2 | 3 | 木兰宽松许可证,第2版 4 | 5 | 2020年1月 http://license.coscl.org.cn/MulanPSL2 6 | 7 | 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 8 | 9 | 0. 定义 10 | 11 | “软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 12 | 13 | “贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 14 | 15 | “贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 16 | 17 | “法人实体” 是指提交贡献的机构及其“关联实体”。 18 | 19 | “关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是 20 | 指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 21 | 22 | 1. 授予版权许可 23 | 24 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可 25 | 以复制、使用、修改、分发其“贡献”,不论修改与否。 26 | 27 | 2. 授予专利许可 28 | 29 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定 30 | 撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡 31 | 献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软 32 | 件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“ 33 | 关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或 34 | 其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权 35 | 行动之日终止。 36 | 37 | 3. 无商标许可 38 | 39 | “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定 40 | 的声明义务而必须使用除外。 41 | 42 | 4. 分发限制 43 | 44 | 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“ 45 | 本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 46 | 47 | 5. 免责声明与责任限制 48 | 49 | “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对 50 | 任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于 51 | 何种法律理论,即使其曾被建议有此种损失的可能性。 52 | 53 | 6. 语言 54 | 55 | “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文 56 | 版为准。 57 | 58 | 条款结束 59 | 60 | 如何将木兰宽松许可证,第2版,应用到您的软件 61 | 62 | 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: 63 | 64 | 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; 65 | 66 | 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; 67 | 68 | 3, 请将如下声明文本放入每个源文件的头部注释中。 69 | 70 | Copyright (c) [Year] [name of copyright holder] 71 | [Software Name] is licensed under Mulan PSL v2. 72 | You can use this software according to the terms and conditions of the Mulan 73 | PSL v2. 74 | You may obtain a copy of Mulan PSL v2 at: 75 | http://license.coscl.org.cn/MulanPSL2 76 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 77 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 78 | NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 79 | See the Mulan PSL v2 for more details. 80 | 81 | Mulan Permissive Software License,Version 2 82 | 83 | Mulan Permissive Software License,Version 2 (Mulan PSL v2) 84 | 85 | January 2020 http://license.coscl.org.cn/MulanPSL2 86 | 87 | Your reproduction, use, modification and distribution of the Software shall 88 | be subject to Mulan PSL v2 (this License) with the following terms and 89 | conditions: 90 | 91 | 0. Definition 92 | 93 | Software means the program and related documents which are licensed under 94 | this License and comprise all Contribution(s). 95 | 96 | Contribution means the copyrightable work licensed by a particular 97 | Contributor under this License. 98 | 99 | Contributor means the Individual or Legal Entity who licenses its 100 | copyrightable work under this License. 101 | 102 | Legal Entity means the entity making a Contribution and all its 103 | Affiliates. 104 | 105 | Affiliates means entities that control, are controlled by, or are under 106 | common control with the acting entity under this License, ‘control’ means 107 | direct or indirect ownership of at least fifty percent (50%) of the voting 108 | power, capital or other securities of controlled or commonly controlled 109 | entity. 110 | 111 | 1. Grant of Copyright License 112 | 113 | Subject to the terms and conditions of this License, each Contributor hereby 114 | grants to you a perpetual, worldwide, royalty-free, non-exclusive, 115 | irrevocable copyright license to reproduce, use, modify, or distribute its 116 | Contribution, with modification or not. 117 | 118 | 2. Grant of Patent License 119 | 120 | Subject to the terms and conditions of this License, each Contributor hereby 121 | grants to you a perpetual, worldwide, royalty-free, non-exclusive, 122 | irrevocable (except for revocation under this Section) patent license to 123 | make, have made, use, offer for sale, sell, import or otherwise transfer its 124 | Contribution, where such patent license is only limited to the patent claims 125 | owned or controlled by such Contributor now or in future which will be 126 | necessarily infringed by its Contribution alone, or by combination of the 127 | Contribution with the Software to which the Contribution was contributed. 128 | The patent license shall not apply to any modification of the Contribution, 129 | and any other combination which includes the Contribution. If you or your 130 | Affiliates directly or indirectly institute patent litigation (including a 131 | cross claim or counterclaim in a litigation) or other patent enforcement 132 | activities against any individual or entity by alleging that the Software or 133 | any Contribution in it infringes patents, then any patent license granted to 134 | you under this License for the Software shall terminate as of the date such 135 | litigation or activity is filed or taken. 136 | 137 | 3. No Trademark License 138 | 139 | No trademark license is granted to use the trade names, trademarks, service 140 | marks, or product names of Contributor, except as required to fulfill notice 141 | requirements in section 4. 142 | 143 | 4. Distribution Restriction 144 | 145 | You may distribute the Software in any medium with or without modification, 146 | whether in source or executable forms, provided that you provide recipients 147 | with a copy of this License and retain copyright, patent, trademark and 148 | disclaimer statements in the Software. 149 | 150 | 5. Disclaimer of Warranty and Limitation of Liability 151 | 152 | THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY 153 | KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR 154 | COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT 155 | LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING 156 | FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO 157 | MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF 158 | THE POSSIBILITY OF SUCH DAMAGES. 159 | 160 | 6. Language 161 | 162 | THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION 163 | AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF 164 | DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION 165 | SHALL PREVAIL. 166 | 167 | END OF THE TERMS AND CONDITIONS 168 | 169 | How to Apply the Mulan Permissive Software License,Version 2 170 | (Mulan PSL v2) to Your Software 171 | 172 | To apply the Mulan PSL v2 to your work, for easy identification by 173 | recipients, you are suggested to complete following three steps: 174 | 175 | i. Fill in the blanks in following statement, including insert your software 176 | name, the year of the first publication of your software, and your name 177 | identified as the copyright owner; 178 | 179 | ii. Create a file named "LICENSE" which contains the whole context of this 180 | License in the first directory of your software package; 181 | 182 | iii. Attach the statement to the appropriate annotated syntax at the 183 | beginning of each source file. 184 | 185 | Copyright (c) [Year] [name of copyright holder] 186 | [Software Name] is licensed under Mulan PSL v2. 187 | You can use this software according to the terms and conditions of the Mulan 188 | PSL v2. 189 | You may obtain a copy of Mulan PSL v2 at: 190 | http://license.coscl.org.cn/MulanPSL2 191 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 192 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 193 | NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 194 | See the Mulan PSL v2 for more details. 195 | -------------------------------------------------------------------------------- /MessageQueue/MqClient/admin.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_ADMIN_H__ 2 | #define __M_ADMIN_H__ 3 | 4 | #include "load.hpp" 5 | #include "../MqCommon/admin.pb.h" 6 | 7 | namespace mq { 8 | class AdminLoad { 9 | private: 10 | void menuAdmin() { 11 | _currentOperation = "menuAdmin"; 12 | printf("************ Admin Menu ************\n"); 13 | printf("********* 1.用户管理 ********\n"); 14 | printf("********* 2.用户数据管理 ********\n"); 15 | printf("********* 3.系统数据管理 ********\n"); 16 | printf("********* 4.订阅管理 ********\n"); 17 | printf("********* 5.服务器器管理 ********\n"); 18 | printf("********* 6.退出 ********\n"); 19 | } 20 | 21 | void userManager() { 22 | // 直接展示当前有哪些用户 23 | _currentOperation = "userManager"; 24 | 25 | // 给出所有用户的信息 26 | 27 | } 28 | 29 | void userDataManager() { 30 | 31 | } 32 | 33 | void systemDataManager() { 34 | 35 | } 36 | 37 | void subscribeManager() { 38 | 39 | } 40 | 41 | void commandLine() { 42 | // [username 当前工作模块]> 43 | std::cout << "[" << _username << " " << _currentOperation << "]> "; 44 | fflush(stdout); 45 | } 46 | 47 | public: 48 | 49 | AdminLoad(mq::Channel::ptr channel) 50 | : _channel(channel), 51 | _username("admin") 52 | {} 53 | 54 | // 管理员事件循环 55 | void adminLoop() { 56 | 57 | } 58 | 59 | private: 60 | std::string _username; 61 | std::string _currentOperation; 62 | std::unordered_map _user_password; 63 | mq::UserType _user_type; 64 | 65 | mq::Channel::ptr _channel; 66 | 67 | }; 68 | } 69 | 70 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqClient/channel.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_CHANNEL_H__ 2 | #define __M_CHANNEL_H__ 3 | 4 | #include "../MqThird/include/codec.h" 5 | #include "../MqCommon/proto.pb.h" 6 | #include "../MqCommon/msg.pb.h" 7 | #include "../MqCommon/user.pb.h" 8 | #include "../MqCommon/admin.pb.h" 9 | #include "../MqCommon/helper.hpp" 10 | #include "../MqCommon/logger.hpp" 11 | #include "../MqCommon/threadpool.hpp" 12 | #include "consumer.hpp" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | namespace mq { 21 | using ProtobufCodecPtr = std::shared_ptr; 22 | using basicConsumeResponcePtr = std::shared_ptr; 23 | using basicCommonResponcePtr = std::shared_ptr; 24 | using MessagePtr = std::shared_ptr; 25 | using UserInfoResponcePtr = std::shared_ptr; 26 | using getExchangeTypeResponcePtr = std::shared_ptr; 27 | 28 | class Channel { 29 | private: 30 | // 基础响应 31 | basicCommonResponcePtr waitResponce(const std::string& rid) { 32 | std::unique_lock lock(_mutex); 33 | _cond.wait(lock, [&rid, this]() { 34 | return _basic_resp.find(rid) != _basic_resp.end(); 35 | }); 36 | basicCommonResponcePtr resp = _basic_resp[rid]; 37 | _basic_resp.erase(rid); 38 | return resp; 39 | } 40 | 41 | // 登陆操作 42 | basicCommonResponcePtr load(const std::string& username, const std::string& password, bool isRegister, UserType user_type) { 43 | userLogin user; 44 | std::string rid = UUIDHelper::uuid(); 45 | user.set_password(password); 46 | user.set_username(username); 47 | user.set_cid(_channel_id); 48 | user.set_rid(rid); 49 | user.set_isregister(isRegister); 50 | if (isRegister == true) 51 | user.set_user_type(user_type); 52 | _codec->send(_conn, user); 53 | basicCommonResponcePtr resp = waitResponce(rid); 54 | return resp; 55 | } 56 | 57 | public: 58 | using ptr = std::shared_ptr; 59 | 60 | Channel(const muduo::net::TcpConnectionPtr& conn, const ProtobufCodecPtr& codec) 61 | : _channel_id(UUIDHelper::uuid()), 62 | _conn(conn), 63 | _codec(codec) 64 | {} 65 | 66 | bool declareExchange(const std::string& ename, ExchangeType etype, bool edurable, 67 | bool eauto_delete, google::protobuf::Map& eargs) { 68 | // 1. 构建对象 69 | std::string rid = UUIDHelper::uuid(); 70 | declareExchangeRequest req; 71 | req.set_cid(_channel_id); 72 | req.set_rid(rid); 73 | req.set_durable(edurable); 74 | req.set_exchange_name(ename); 75 | req.set_exchange_type(etype); 76 | req.set_auto_delete(eauto_delete); 77 | req.mutable_args()->swap(eargs); 78 | // 2. 将构建的对象发送出去 79 | // protobuf底层设计了自己的发送和接收缓冲区,发送和接收是异步工作的 80 | // 所以只有对方确认收到(等待响应)之后我们才可以返回 81 | _codec->send(_conn, req); 82 | // 3. 等待响应 83 | basicCommonResponcePtr resp = waitResponce(rid); 84 | // 4. 返回 85 | return resp->ok(); 86 | } 87 | 88 | void deleteExchange(const std::string& ename) { 89 | std::string rid = UUIDHelper::uuid(); 90 | deleteExchangeRequest req; 91 | req.set_cid(_channel_id); 92 | req.set_rid(rid); 93 | req.set_exchange_name(ename); 94 | _codec->send(_conn, req); 95 | waitResponce(rid); 96 | } 97 | 98 | bool declareQueue(const std::string& qname, bool qdurable, 99 | bool qexclusive, bool qauto_delete, 100 | google::protobuf::Map& qargs) { 101 | 102 | std::string rid = UUIDHelper::uuid(); 103 | declareQueueRequest req; 104 | req.set_cid(_channel_id); 105 | req.set_rid(rid); 106 | req.set_durable(qdurable); 107 | req.set_queue_name(qname); 108 | req.set_auto_delete(qauto_delete); 109 | req.mutable_args()->swap(qargs); 110 | req.set_exclusive(qexclusive); 111 | 112 | _codec->send(_conn, req); 113 | // 3. 等待响应 114 | basicCommonResponcePtr resp = waitResponce(rid); 115 | // 4. 返回 116 | return resp->ok(); 117 | } 118 | 119 | void deleteQueue(const std::string& qname) { 120 | std::string rid = UUIDHelper::uuid(); 121 | deleteQueueRequest req; 122 | req.set_cid(_channel_id); 123 | req.set_rid(rid); 124 | req.set_queue_name(qname); 125 | _codec->send(_conn, req); 126 | 127 | waitResponce(rid); 128 | } 129 | 130 | bool queueBind(const std::string& ename, const std::string& qname, const std::string& key) { 131 | std::string rid = UUIDHelper::uuid(); 132 | queueBindRequest req; 133 | req.set_cid(_channel_id); 134 | req.set_rid(rid); 135 | req.set_queue_name(qname); 136 | req.set_exchange_name(ename); 137 | req.set_binding_key(key); 138 | 139 | _codec->send(_conn, req); 140 | // 3. 等待响应 141 | basicCommonResponcePtr resp = waitResponce(rid); 142 | // 4. 返回 143 | return resp->ok(); 144 | } 145 | 146 | void queueUnBind(const std::string& ename, const std::string& qname) { 147 | std::string rid = UUIDHelper::uuid(); 148 | queueUnBindRequest req; 149 | req.set_cid(_channel_id); 150 | req.set_rid(rid); 151 | req.set_queue_name(qname); 152 | req.set_exchange_name(ename); 153 | _codec->send(_conn, req); 154 | 155 | waitResponce(rid); 156 | } 157 | 158 | void basicPublish(const std::string& ename, const BasicProperties* bp, const std::string& body) { 159 | // 发送消息给交换机,让交换机来自动匹配消息发给哪个队列 160 | std::string rid = UUIDHelper::uuid(); 161 | basicPublishRequest req; 162 | req.set_cid(_channel_id); 163 | req.set_rid(rid); 164 | req.set_exchange_name(ename); 165 | req.set_body(body); 166 | if (bp != nullptr) { 167 | req.mutable_properties()->set_id(bp->id()); 168 | req.mutable_properties()->set_delivery_mode(bp->delivery_mode()); 169 | req.mutable_properties()->set_routing_key(bp->routing_key()); 170 | } 171 | _codec->send(_conn, req); 172 | 173 | waitResponce(rid); 174 | } 175 | 176 | std::pair loadPublish(const std::string& username, const std::string& password, UserType user_type) { 177 | basicCommonResponcePtr resp = this->load(username, password, false, user_type); 178 | // 返回类型和是否登陆成功 179 | return std::make_pair(resp->ok(), resp->user_type()); 180 | } 181 | 182 | std::pair registerPublish(const std::string& username, const std::string& password, UserType user_type) { 183 | basicCommonResponcePtr resp = this->load(username, password, true, user_type); 184 | return std::make_pair(resp->ok(), resp->user_type()); 185 | } 186 | 187 | void logoutPublish(const std::string& username, UserType user_type) { 188 | userLogout req; 189 | std::string rid = UUIDHelper::uuid(); 190 | req.set_cid(_channel_id); 191 | req.set_rid(rid); 192 | req.set_user_type(user_type); 193 | req.set_username(username); 194 | _codec->send(_conn, req); 195 | waitResponce(rid); 196 | } 197 | 198 | void getAllUsersPublish() { 199 | userInfoRequest req; 200 | std::string rid = UUIDHelper::uuid(); 201 | req.set_cid(_channel_id); 202 | req.set_rid(rid); 203 | _codec->send(_conn, req); 204 | } 205 | 206 | void getExchangeTypePublish(const std::string& ename) { 207 | getExchangeTypeRequest req; 208 | std::string rid = UUIDHelper::uuid(); 209 | req.set_cid(_channel_id); 210 | req.set_rid(rid); 211 | req.set_exchange_name(ename); 212 | _codec->send(_conn, req); 213 | } 214 | 215 | void garbageRecivePublish() { 216 | garbageRecive req; 217 | std::string rid = UUIDHelper::uuid(); 218 | req.set_cid(_channel_id); 219 | req.set_rid(rid); 220 | _codec->send(_conn, req); 221 | waitResponce(rid); 222 | } 223 | 224 | void basicAck(const std::string& msg_id) { 225 | if (_consumer.get() == nullptr) { 226 | DLOG("确认消息时,找不到对应的消费者信息\n"); 227 | return; 228 | } 229 | std::string rid = UUIDHelper::uuid(); 230 | basicAckRequest req; 231 | req.set_cid(_channel_id); 232 | req.set_rid(rid); 233 | req.set_queue_name(_consumer->qname); 234 | req.set_message_id(msg_id); 235 | _codec->send(_conn, req); 236 | 237 | waitResponce(rid); 238 | } 239 | 240 | // 订阅消息 241 | bool basicConsume(const std::string& consumer_tag, 242 | const std::string& qname, bool auto_ack, const ConsumerCallback& cb) { 243 | if (_consumer.get() != nullptr) { 244 | DLOG("消费者已经存在,不用订阅\n"); 245 | return false; 246 | } 247 | std::string rid = UUIDHelper::uuid(); 248 | basicConsumeRequest req; 249 | req.set_rid(rid); 250 | req.set_cid(_channel_id); 251 | req.set_queue_name(qname); 252 | req.set_consumer_tag(consumer_tag); 253 | req.set_auto_ack(auto_ack); 254 | _codec->send(_conn, req); 255 | 256 | basicCommonResponcePtr resp = waitResponce(rid); 257 | if (resp->ok() == false) { 258 | DLOG("添加订阅失败\n"); 259 | return false; 260 | } 261 | // 生成当前信道对应的消费者 262 | _consumer = std::make_shared(consumer_tag, qname, auto_ack, cb); 263 | return true; 264 | } 265 | 266 | void basicCancel() { 267 | if (_consumer.get() == nullptr) 268 | return; 269 | std::string rid = UUIDHelper::uuid(); 270 | basicCancelRequest req; 271 | req.set_cid(_channel_id); 272 | req.set_rid(rid); 273 | req.set_consumer_tag(_consumer->tag); 274 | req.set_queue_name(_consumer->qname); 275 | _codec->send(_conn, req); 276 | 277 | waitResponce(rid); 278 | // 取消订阅,也就将当前的消费者重置 279 | _consumer.reset(); 280 | } 281 | 282 | std::string cid() { 283 | return _channel_id; 284 | } 285 | 286 | ~Channel() { 287 | basicCancel(); 288 | } 289 | 290 | void setArgs(const std::string& args) { 291 | { 292 | std::lock_guard lock(_mutex); 293 | _other_args = args; 294 | } 295 | _cond.notify_all(); // 通知等待线程条件已满足 296 | } 297 | 298 | public: 299 | // 收到消息之后,向对应响应消息队列中加入响应消息 300 | void putBasicResponce(const basicCommonResponcePtr& resp) { 301 | std::unique_lock lock(_mutex); 302 | _basic_resp[resp->rid()] = resp; 303 | // 从外部接收到消息之后,唤醒之前等待的线程 304 | _cond.notify_all(); 305 | } 306 | 307 | // 收到响应之后,需要找到对应的消费者去处理消息 308 | void consume(const basicConsumeResponcePtr& resp) { 309 | if (_consumer.get() == nullptr) { 310 | DLOG("处理消息时,订阅者为找到\n"); 311 | return; 312 | } 313 | if (_consumer->tag != resp->consumer_tag()) { 314 | DLOG("处理消息时,订阅者和请求消息不对应\n"); 315 | return; 316 | } 317 | _consumer->callback(resp->consumer_tag(), resp->mutable_properties(), resp->body()); 318 | } 319 | 320 | void getAllUsers(const UserInfoResponcePtr& resp) { 321 | this->setArgs(resp->user_infos()); 322 | } 323 | 324 | void getExchangeType(const getExchangeTypeResponcePtr& resp) { 325 | this->setArgs(std::to_string(resp->type())); 326 | } 327 | 328 | bool openChannel() { 329 | std::string rid = UUIDHelper::uuid(); 330 | openChannelRequest req; 331 | req.set_cid(_channel_id); 332 | req.set_rid(rid); 333 | _codec->send(_conn, req); 334 | basicCommonResponcePtr resp = waitResponce(rid); 335 | return resp->ok(); 336 | } 337 | 338 | void closeChannel() { 339 | std::string rid = UUIDHelper::uuid(); 340 | closeChannelRequest req; 341 | req.set_cid(_channel_id); 342 | req.set_rid(rid); 343 | _codec->send(_conn, req); 344 | waitResponce(rid); 345 | } 346 | 347 | std::string getArgs() { 348 | std::unique_lock lock(_mutex); 349 | _cond.wait(lock, [this]() { return !_other_args.empty(); }); // 等待条件满足 350 | std::string ret(_other_args); 351 | _other_args.clear(); 352 | return ret; 353 | } 354 | private: 355 | std::string _channel_id; // 信道id 356 | muduo::net::TcpConnectionPtr _conn; // 信道关联的网络通信对象 357 | ProtobufCodecPtr _codec; // 协议处理对象 358 | Consumer::ptr _consumer; // 信道关联的消费者 359 | std::mutex _mutex; // 锁:和条件变量共同维护响应和处理的先后顺序 360 | std::condition_variable _cond; // 条件变量 361 | std::unordered_map _basic_resp; // 请求对应的响应信息队列 362 | 363 | std::string _other_args; 364 | }; 365 | 366 | class ChannelManager { 367 | public: 368 | using ptr = std::shared_ptr; 369 | 370 | ChannelManager() {} 371 | 372 | // 创建信道 373 | Channel::ptr create(const muduo::net::TcpConnectionPtr& conn, const ProtobufCodecPtr& codec) { 374 | std::unique_lock lock(_mutex); 375 | Channel::ptr channel = std::make_shared(conn, codec); 376 | std::string cid = channel->cid(); 377 | _channels[cid] = channel; 378 | return channel; 379 | } 380 | 381 | // 移除信道 382 | void remove(const std::string& cid) { 383 | std::unique_lock lock(_mutex); 384 | _channels.erase(cid); 385 | } 386 | 387 | // 获取指定的队列 388 | Channel::ptr get(const std::string& cid) { 389 | std::unique_lock lock(_mutex); 390 | auto it = _channels.find(cid); 391 | if (it == _channels.end()) 392 | return Channel::ptr(); 393 | return it->second; 394 | } 395 | 396 | private: 397 | std::mutex _mutex; 398 | std::unordered_map _channels; 399 | }; 400 | } 401 | 402 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqClient/client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqClient/client -------------------------------------------------------------------------------- /MessageQueue/MqClient/client.cc: -------------------------------------------------------------------------------- 1 | #include "connection.hpp" 2 | #include "../MqCommon/helper.hpp" 3 | #include "load.hpp" 4 | 5 | int main() { 6 | mq::AsyncWorker::ptr awp = std::make_shared(); 7 | mq::Connection::ptr conn = std::make_shared("127.0.0.1", 8085, awp); 8 | mq::Channel::ptr channel = conn->openChannel(); 9 | 10 | mq::LoadHelper load(channel, ""); 11 | std::pair isLoad = load.userLoad(); 12 | 13 | if (!isLoad.first) { 14 | conn->closeChannel(channel); 15 | return 1; 16 | } 17 | 18 | if (isLoad.second == mq::ADMIN) 19 | load.adminLoop(); 20 | else if (isLoad.second == mq::PUBLISHER) 21 | load.publisherLoop(); 22 | else 23 | load.reciverLoop(); 24 | 25 | google::protobuf::Map google_tmp1; 26 | google::protobuf::Map google_tmp2; 27 | google::protobuf::Map google_tmp3; 28 | 29 | // 主题匹配发送 30 | //channel->declareExchange("exchange1", mq::ExchangeType::TOPIC, true, false, google_tmp1); 31 | // // 直接匹配发送 32 | // channel->declareExchange("exchange1", mq::ExchangeType::DIRECT, true, false, google_tmp1); 33 | // // 广播匹配发送 34 | // channel->declareExchange("exchange1", mq::ExchangeType::FANOUT, true, false, google_tmp1); 35 | // channel->declareQueue("queue1", true, false, false, google_tmp2); 36 | // channel->declareQueue("queue2", true, false, false, google_tmp3); 37 | // channel->queueBind("exchange1", "queue1", "news.sport.#"); 38 | // channel->queueBind("exchange1", "queue2", "news.music.#"); 39 | 40 | // // 循环发送信息 41 | // for (int i = 0; i < 10; i++) { 42 | // mq::BasicProperties bp; 43 | // bp.set_id(mq::UUIDHelper::uuid()); 44 | // bp.set_routing_key("news.music.pop"); 45 | // bp.set_delivery_mode(mq::DeliveryMode::DURABLE); 46 | // channel->basicPublish("exchange1", &bp, "hello world-" + std::to_string(i)); 47 | // } 48 | 49 | // mq::BasicProperties bp; 50 | // bp.set_id(mq::UUIDHelper::uuid()); 51 | // bp.set_routing_key("queue1"); 52 | // bp.set_delivery_mode(mq::DeliveryMode::DURABLE); 53 | // channel->basicPublish("exchange1", &bp, "hello world-" + std::to_string(10)); 54 | 55 | // bp.set_routing_key("news.sport.football"); 56 | // channel->basicPublish("exchange1", &bp, "hello world-" + std::to_string(11)); 57 | 58 | // // 先使用广播发送运动新闻 59 | // mq::BasicProperties bp; 60 | // bp.set_id(mq::UUIDHelper::uuid()); 61 | // bp.set_routing_key("news.sport.#"); 62 | // bp.set_delivery_mode(mq::DeliveryMode::DURABLE); 63 | // std::string body; 64 | // mq::FileHelper filehelper("./sportnews.txt"); 65 | // filehelper.read(body); 66 | // channel->basicPublish("exchange1", &bp, body); 67 | 68 | // bp.set_id(mq::UUIDHelper::uuid()); 69 | // bp.set_routing_key("news.music.#"); 70 | // bp.set_delivery_mode(mq::DeliveryMode::DURABLE); 71 | // std::string body2; 72 | // mq::FileHelper filehelper2("./musicnews.txt"); 73 | // filehelper2.read(body2); 74 | // channel->basicPublish("exchange1", &bp, body2); 75 | 76 | conn->closeChannel(channel); 77 | return 0; 78 | } -------------------------------------------------------------------------------- /MessageQueue/MqClient/connection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_CONNECTION_H__ 2 | #define __M_CONNECTION_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "../MqThird/include/codec.h" 11 | #include "../MqThird/include/dispatcher.h" 12 | #include "../MqCommon/user.pb.h" 13 | #include "../MqCommon/color.hpp" 14 | #include "channel.hpp" 15 | #include "worker.hpp" 16 | 17 | 18 | namespace mq { 19 | 20 | class Connection { 21 | private: 22 | // 对于该连接模块,其本质就是属于客户端模块,对于客户端而言,其实际是和信道直接关联的 23 | // 不过在该代码中弱化了客户端的概念 24 | 25 | // 获取一个消息,然后将消息加入到信道中 26 | void onBasicResponce(const muduo::net::TcpConnectionPtr& conn, const basicCommonResponcePtr& message, muduo::Timestamp) { 27 | // 首先要先获取信道 28 | Channel::ptr channel = _channels->get(message->cid()); 29 | if (channel.get() == nullptr) { 30 | DLOG("没有找到对应的信道\n"); 31 | return; 32 | } 33 | // 向响应队列中加入消息 34 | channel->putBasicResponce(message); 35 | } 36 | 37 | // 将获取的消息放入多线程中进行处理 38 | void onConsumeResponce(const muduo::net::TcpConnectionPtr& conn, const basicConsumeResponcePtr& message, muduo::Timestamp) { 39 | Channel::ptr channel = _channels->get(message->cid()); 40 | if (channel.get() == nullptr) { 41 | DLOG("没有找到对应的信道\n"); 42 | return; 43 | } 44 | // 然后将消息处理任务当道线程中 45 | _worker->pool.push([channel, message](){ 46 | channel->consume(message); 47 | }); 48 | } 49 | 50 | void onUserInfoResponce(const muduo::net::TcpConnectionPtr& conn, const UserInfoResponcePtr& message, muduo::Timestamp) { 51 | Channel::ptr channel = _channels->get(message->cid()); 52 | if (channel.get() == nullptr) { 53 | DLOG("没有找到对应的信道\n"); 54 | return; 55 | } 56 | // 然后将消息处理任务当道线程中 57 | _worker->pool.push([channel, message](){ 58 | channel->getAllUsers(message); 59 | }); 60 | } 61 | 62 | void onGetExchangeTypeResponce(const muduo::net::TcpConnectionPtr& conn, const getExchangeTypeResponcePtr& message, muduo::Timestamp) { 63 | Channel::ptr channel = _channels->get(message->cid()); 64 | if (channel.get() == nullptr) { 65 | DLOG("没有找到对应的信道\n"); 66 | return; 67 | } 68 | _worker->pool.push([channel, message](){ 69 | // channel->getAllUsers(message); 70 | channel->getExchangeType(message); 71 | }); 72 | } 73 | 74 | void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp) { 75 | LOG_INFO << "onUnknownMessage: " << message->GetTypeName(); 76 | conn->shutdown(); 77 | } 78 | 79 | void onConnection(const muduo::net::TcpConnectionPtr&conn){ 80 | if (conn->connected()) { 81 | _latch.countDown();//唤醒主线程中的阻塞 82 | _conn = conn; 83 | }else { 84 | //连接关闭时的操作 85 | _conn.reset(); 86 | } 87 | } 88 | 89 | void connect() { 90 | _client.connect(); 91 | _latch.wait(); //阻塞等待,直到连接建立成功 92 | } 93 | public: 94 | using ptr = std::shared_ptr; 95 | 96 | Connection(const std::string &sip, int sport, const AsyncWorker::ptr& worker) 97 | : _worker(worker), 98 | _latch(1), 99 | _client(worker->loopthread.startLoop(), muduo::net::InetAddress(sip, sport), "Client"), 100 | _dispatcher(std::bind(&Connection::onUnknownMessage, this, std::placeholders::_1, 101 | std::placeholders::_2, std::placeholders::_3)), 102 | _codec(std::make_shared(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 103 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))), 104 | _channels(std::make_shared()) 105 | { 106 | 107 | 108 | _dispatcher.registerMessageCallback(std::bind(&Connection::onBasicResponce, this, 109 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 110 | 111 | _dispatcher.registerMessageCallback(std::bind(&Connection::onConsumeResponce, this, 112 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 113 | 114 | _dispatcher.registerMessageCallback(std::bind(&Connection::onUserInfoResponce, this, 115 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 116 | 117 | _dispatcher.registerMessageCallback(std::bind(&Connection::onGetExchangeTypeResponce, this, 118 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 119 | 120 | _client.setMessageCallback(std::bind(&ProtobufCodec::onMessage, _codec.get(), 121 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 122 | 123 | _client.setConnectionCallback(std::bind(&Connection::onConnection, this, std::placeholders::_1)); 124 | 125 | // 构造的时候就直接开始连接 126 | this->connect(); 127 | } 128 | 129 | Channel::ptr openChannel() { 130 | Channel::ptr channel = _channels->create(_conn, _codec); 131 | bool ret = channel->openChannel(); 132 | if (ret == false) { 133 | DLOG("创建信道失败\n"); 134 | return Channel::ptr(); 135 | } 136 | return channel; 137 | } 138 | 139 | void closeChannel(const Channel::ptr& channel) { 140 | channel->closeChannel(); 141 | _channels->remove(channel->cid()); 142 | } 143 | 144 | private: 145 | muduo::CountDownLatch _latch; //实现同步的 146 | muduo::net::TcpConnectionPtr _conn; //客户端对应的连接 147 | muduo::net::TcpClient _client; //客户端 148 | ProtobufDispatcher _dispatcher; //请求分发器 149 | ProtobufCodecPtr _codec; //协议处理器 150 | AsyncWorker::ptr _worker; // 任务处理线程 & IO事件监控线程 151 | ChannelManager::ptr _channels; // 信道管理 152 | 153 | }; 154 | 155 | } 156 | 157 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqClient/consume_client.cc: -------------------------------------------------------------------------------- 1 | #include "connection.hpp" 2 | 3 | // 收到消息之后的回调函数 4 | void cb(const mq::Channel::ptr& channel, const std::string& consumer_tag, const mq::BasicProperties* bp, const std::string& body) { 5 | std::cout << consumer_tag << " 得到消息: " << body << std::endl; 6 | channel->basicAck(bp->id()); 7 | } 8 | 9 | int main(int argc ,char* argv[]) { 10 | if (argc != 2) { 11 | DLOG("please input the two args: ./consume_client queue1\n"); 12 | return -1; 13 | } 14 | // 创建连接以及信道 15 | mq::AsyncWorker::ptr awp = std::make_shared(); 16 | mq::Connection::ptr conn = std::make_shared("127.0.0.1", 8085, awp); 17 | mq::Channel::ptr channel = conn->openChannel(); 18 | 19 | 20 | // 主题匹配接收 21 | google::protobuf::Map google_tmp; 22 | 23 | // // 直接匹配接收 24 | // channel->declareExchange("exchange1", mq::ExchangeType::DIRECT, true, false, google_tmp); 25 | // // 广播匹配接收 26 | channel->declareExchange("exchange1", mq::ExchangeType::FANOUT, true, false, google_tmp); 27 | 28 | // channel->declareExchange("exchange1", mq::ExchangeType::TOPIC, true, false, google_tmp); 29 | channel->declareQueue("queue1", true, false, false, google_tmp); 30 | channel->declareQueue("queue2", true, false, false, google_tmp); 31 | channel->queueBind("exchange1", "queue1", "queue1"); 32 | channel->queueBind("exchange1", "queue2", "news.music.#"); 33 | 34 | 35 | auto callback = std::bind(cb, channel, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); 36 | 37 | 38 | channel->basicConsume("consumer1", argv[1], false, callback); 39 | 40 | // 主线程在这循环等待 41 | while (true) 42 | std::this_thread::sleep_for(std::chrono::seconds(3)); 43 | 44 | conn->closeChannel(channel); 45 | 46 | } -------------------------------------------------------------------------------- /MessageQueue/MqClient/consumer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_CONSUMER_H__ 2 | #define __M_CONSUMER_H__ 3 | 4 | #include "../MqCommon/msg.pb.h" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/logger.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace mq { 14 | using ConsumerCallback = std::function; 15 | 16 | struct Consumer { 17 | using ptr = std::shared_ptr; 18 | 19 | std::string tag; // 消费者标识 ----> 标识订阅的消费者 20 | std::string qname; // 消费者绑定队列名称 ----> 标识订阅者对应的队列 21 | bool auto_ack; // 是否自动确认 ----> 对于队列发送过来的消息是否自动确认 22 | ConsumerCallback callback; // 回调函数 ----> 获取消息之后处理的回调函数 23 | 24 | Consumer() {} 25 | 26 | Consumer(const std::string& ctag, const std::string& queue_name, bool ack, const ConsumerCallback& cb) 27 | : tag(ctag), 28 | qname(queue_name), 29 | auto_ack(ack), 30 | callback(cb) 31 | {} 32 | }; 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqClient/data/admin/binding.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqClient/data/admin/binding.txt -------------------------------------------------------------------------------- /MessageQueue/MqClient/data/admin/exchange.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqClient/data/admin/exchange.txt -------------------------------------------------------------------------------- /MessageQueue/MqClient/data/admin/info.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqClient/data/admin/info.txt -------------------------------------------------------------------------------- /MessageQueue/MqClient/data/admin/queue.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqClient/data/admin/queue.txt -------------------------------------------------------------------------------- /MessageQueue/MqClient/makefile: -------------------------------------------------------------------------------- 1 | all:client 2 | 3 | client:client.cc ../MqCommon/proto.pb.cc ../MqThird/include/codec.cc ../MqCommon/msg.pb.cc ../MqCommon/user.pb.cc ../MqCommon/admin.pb.cc 4 | g++ -o $@ $^ -std=c++11 -lmuduo_net -lmuduo_base -lpthread -lz -lprotobuf -g -lstdc++fs 5 | 6 | 7 | .PONHY:clean 8 | clean: 9 | rm -f client -------------------------------------------------------------------------------- /MessageQueue/MqClient/worker.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_WORKER_H__ 2 | #define __M_WORKER_H__ 3 | 4 | #include 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/logger.hpp" 7 | #include "../MqCommon/threadpool.hpp" 8 | 9 | namespace mq { 10 | class AsyncWorker { 11 | // 这一个对象可以用于多个连接使用 12 | public: 13 | using ptr = std::shared_ptr; 14 | 15 | threadpool pool; // 事件处理线程池 16 | muduo::net::EventLoopThread loopthread; // 用于循环监控io事件 17 | }; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqCommon/admin.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package mq; 4 | 5 | enum UserOptions { 6 | SELECT = 0; // 消息接收用户 7 | MODIFY = 1; // 消息发布用户 8 | DELETE = 2; // 管理员 9 | }; 10 | 11 | message userInfoRequest { 12 | string rid = 1; // 消息id 13 | string cid = 2; // 信道id 14 | } 15 | 16 | message userInfoResponce { 17 | string rid = 1; // 消息id 18 | string cid = 2; // 信道id 19 | string user_infos = 3; 20 | } 21 | 22 | // 查看当前都存在哪些用户 23 | // 只要userInfoRequest发送出去了 24 | // 就将所有的用户信息转发过来 25 | 26 | // 还需要查看当前用户的订阅关系 27 | // 也就是需要根据当前的所有用户 28 | 29 | message garbageRecive { 30 | string rid = 1; // 消息id 31 | string cid = 2; // 信道id 32 | } 33 | 34 | message getExchangeTypeRequest { 35 | string rid = 1; // 消息id 36 | string cid = 2; // 信道id 37 | string exchange_name = 3; 38 | } 39 | 40 | message getExchangeTypeResponce { 41 | string rid = 1; // 消息id 42 | string cid = 2; // 信道id 43 | uint32 type = 3; 44 | // 0表示位置 1表示直连 2表示广播 3表示主题 45 | } -------------------------------------------------------------------------------- /MessageQueue/MqCommon/color.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_COLOR_H__ 2 | #define __M_COLOR_H__ 3 | 4 | namespace mq { 5 | // 定义一些颜色代码 6 | #define RESET "\033[0m" // 重置颜色 7 | #define RED "\033[31m" // 红色 8 | #define GREEN "\033[32m" // 绿色 9 | #define YELLOW "\033[33m" // 黄色 10 | #define BLUE "\033[34m" // 蓝色 11 | #define MAGENTA "\033[35m" // 紫色 12 | #define CYAN "\033[36m" // 青色 13 | } 14 | 15 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqCommon/helper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_HELPER_H__ 2 | #define __M_HELPER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "logger.hpp" 19 | 20 | namespace mq { 21 | 22 | class SqliteHelper { 23 | private: 24 | // 对数据处理对饮的回调函数 25 | typedef int(*SqliteCallback)(void*, int, char**, char**); 26 | public: 27 | SqliteHelper(const std::string& dbfile) 28 | : _dbfile(dbfile), 29 | _handler(nullptr) 30 | {} 31 | 32 | bool open(int safe_lavel = SQLITE_OPEN_FULLMUTEX) { 33 | int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_lavel, nullptr); 34 | if (ret != SQLITE_OK) { 35 | ELOG("创建/打开sqlite失败: %s\n", sqlite3_errmsg(_handler)); 36 | return false; 37 | } 38 | return true; 39 | } 40 | 41 | bool exec(const std::string& sql, SqliteCallback cb, void* arg) { 42 | int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr); 43 | if (ret != SQLITE_OK) { 44 | ELOG("%s \n, 执行语句失败: %s\n", sql.c_str(), sqlite3_errmsg(_handler)); 45 | return false; 46 | } 47 | return true; 48 | } 49 | 50 | void close() { 51 | if (_handler) 52 | sqlite3_close_v2(_handler); 53 | } 54 | 55 | private: 56 | std::string _dbfile; 57 | sqlite3* _handler; 58 | }; 59 | 60 | class StrHelper { 61 | public: 62 | static size_t split(const std::string& str, const std::string& sep, std::vector& result) { 63 | // new....music.#pop... 64 | // 该函数的作用就是将字符串按照某一特定的字符分割开 65 | size_t pos = 0, index = 0; 66 | while (index < str.size()) { 67 | pos = str.find(sep, index); 68 | if (pos == std::string::npos) { 69 | // 最后一次没有找到 70 | std::string tmp = str.substr(index); 71 | result.push_back(std::move(tmp)); 72 | return result.size(); 73 | } 74 | if (index == pos) { 75 | index = pos + sep.size(); 76 | continue; 77 | } 78 | std::string tmp = str.substr(index, pos - index); 79 | result.push_back(std::move(tmp)); 80 | index = pos + sep.size(); 81 | } 82 | return result.size(); 83 | } 84 | }; 85 | 86 | class UUIDHelper { 87 | public: 88 | static std::string uuid() { 89 | // uuid的数据格式为一个8-4-4-4-12的16进制字符串,如:7a91a05f-52a1-6a01-0000-000000000001 90 | std::random_device rd; 91 | // 使用一个机器随机数作为伪随机数的种子 92 | // 机器数:使用硬件生成的一个数据,生成效率较低 93 | std::mt19937_64 generator(rd()); 94 | // 生成的数据范围为0~255 95 | std::uniform_int_distribution distribution(0, 255); 96 | std::stringstream ss; 97 | for (int i = 0; i < 8; i++) { 98 | ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator); 99 | if (i == 3 || i == 5 || i == 7) 100 | ss << "-"; 101 | } 102 | // std::cout << ss.str() << std::endl; 103 | static std::atomic seq(1); 104 | size_t num = seq.fetch_add(1); 105 | for (int i = 7; i >= 0; i--) { 106 | ss << std::setw(2) << std::setfill('0') << std::hex << (num >> (i * 8)); 107 | if (i == 6) 108 | ss << "-"; 109 | } 110 | return ss.str(); 111 | } 112 | }; 113 | 114 | class FileHelper { 115 | public: 116 | FileHelper(const std::string& filename) 117 | : _filename(filename) 118 | {} 119 | 120 | bool exists() { 121 | struct stat st; 122 | return (stat(_filename.c_str(), &st) == 0); 123 | } 124 | 125 | size_t size() { 126 | // 获取当前文件的大小 127 | struct stat st; 128 | if (!exists()) 129 | return 0; 130 | stat(_filename.c_str(), &st); 131 | return st.st_size; 132 | } 133 | 134 | // 从offset位置开始读取len长度的内容 135 | bool read(char* body, size_t offset, size_t len) { 136 | std::ifstream ifs(_filename.c_str(), std::ios::binary | std::ios::in); 137 | if (!ifs.is_open()) { 138 | ELOG("%s, 打开文件失败\n", _filename.c_str()); 139 | return false; 140 | } 141 | ifs.seekg(offset, std::ios::beg); 142 | ifs.read(body, len); 143 | if (!ifs.good()) { 144 | ELOG("%s, 文件读取失败\n", _filename.c_str()); 145 | ifs.close(); 146 | return false; 147 | } 148 | ifs.close(); 149 | return true; 150 | } 151 | 152 | // 读取所有数据到body中 153 | bool read(std::string& body) { 154 | size_t filesize = this->size(); 155 | body.resize(filesize); 156 | return this->read(&body[0], 0, filesize); 157 | } 158 | 159 | // 从文件offset位置写入len长度的内容 160 | bool write(const char* body, size_t offset, size_t len) { 161 | std::fstream fs(_filename.c_str(), std::ios::binary | std::ios::in | std::ios::out); 162 | if (!fs.is_open()) { 163 | ELOG("%s, 打开文件失败\n", _filename.c_str()); 164 | return false; 165 | } 166 | fs.seekp(offset, std::ios::beg); 167 | fs.write(body, len); 168 | if (!fs.good()) { 169 | ELOG("%s, 文件写入失败\n", _filename.c_str()); 170 | fs.close(); 171 | return false; 172 | } 173 | 174 | fs.close(); 175 | return true; 176 | } 177 | 178 | // 写入body的所有数据 179 | bool write(const std::string& body) { 180 | return this->write(body.c_str(), 0, body.size()); 181 | } 182 | 183 | // 文件重命名 184 | bool rename(const std::string& new_name) { 185 | std::string old_name(_filename); 186 | int ret = ::rename(old_name.c_str(), new_name.c_str()); 187 | if (ret == 0) { 188 | _filename = new_name; 189 | return true; 190 | } else { 191 | return false; 192 | } 193 | } 194 | 195 | static bool createFile(const std::string& filename) { 196 | // 只有当创建的文件具有写属性的时候才会创建,若只有读属性则不可以创建 197 | std::ofstream ofs(filename.c_str(), std::ios::binary | std::ios::out); 198 | if (!ofs.is_open()) { 199 | ELOG("%s, 文件创建失败:%s\n", filename.c_str(), strerror(errno)); 200 | return false; 201 | } 202 | ofs.close(); 203 | return true; 204 | } 205 | 206 | static bool removeFile(const std::string& filename) { 207 | return (::remove(filename.c_str()) == 0); 208 | } 209 | 210 | static bool createDirectory(const std::string& path) { 211 | // "aaa/ccc/sss/qwqw" 212 | size_t pos = 0, index = 0; 213 | std::string sep = "/"; 214 | while (index < path.size()) { 215 | pos = path.find(sep, index); 216 | if (pos == std::string::npos) { 217 | int ret = ::mkdir(path.c_str(), 0775); 218 | if (ret != 0) { 219 | return false; 220 | } else { 221 | return true; 222 | } 223 | } 224 | std::string sub_path = path.substr(0, pos); 225 | int res = ::mkdir(sub_path.c_str(), 0775); 226 | if (res != 0 && errno != EEXIST) { 227 | ELOG("%s 创建目录失败:%s\n", sub_path.c_str(), strerror(errno)); 228 | return false; 229 | } 230 | index = pos + sep.size(); 231 | } 232 | 233 | return true; 234 | } 235 | 236 | static bool removeDirectory(const std::string& path) { 237 | // 使用指令删除目录 238 | std::string cmd = "rm -rf " + path; 239 | return (::system(cmd.c_str()) != 0); 240 | } 241 | 242 | static std::string parentDirectory(const std::string& file_path) { 243 | // "aaa/ccc/sss/qwqw" 244 | size_t pos = file_path.find_last_of("/"); 245 | if (pos == std::string::npos) 246 | return "./"; 247 | return file_path.substr(0, pos); 248 | } 249 | 250 | private: 251 | std::string _filename; 252 | }; 253 | } 254 | 255 | 256 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqCommon/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_LOG_H__ 2 | #define __M_LOG_H__ 3 | 4 | #include 5 | #include 6 | 7 | namespace mq { 8 | #define DEBUG_LEVEL 0 9 | #define INFO_LEVEL 1 10 | #define ERROR_LEVEL 2 11 | #define DEFAULT_LEVEL DEBUG_LEVEL 12 | // [current time][current file][line in error]... 13 | #define LOG(log_level_str, log_level, format, ...) do { \ 14 | if (log_level >= DEFAULT_LEVEL) { \ 15 | time_t t = time(nullptr); \ 16 | struct tm* ptm = localtime(&t); \ 17 | char timestr[32]; \ 18 | strftime(timestr, 31, "%H:%M:%S", ptm); \ 19 | printf("[%s][%s][%s:%d] " format "", log_level_str, timestr, __FILE__, __LINE__, ##__VA_ARGS__); \ 20 | } \ 21 | } while(0) 22 | 23 | #define DLOG(format, ...) LOG("DEBUG", DEBUG_LEVEL, format, ##__VA_ARGS__) 24 | #define ILOG(format, ...) LOG("INFO", DEBUG_LEVEL, format, ##__VA_ARGS__) 25 | #define ELOG(format, ...) LOG("ERROR", DEBUG_LEVEL, format, ##__VA_ARGS__) 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqCommon/msg.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package mq; 4 | 5 | // 交换机类型 6 | enum ExchangeType { 7 | UNKNOWNTYPE = 0;// 未知模式 8 | DIRECT = 1; // 直连模式 9 | FANOUT = 2; // 广播模式 10 | TOPIC = 3; // 主题模式 11 | }; 12 | 13 | // 消息传递模式,是否持久化 14 | enum DeliveryMode { 15 | UNKNOWNMODE = 0; // 未知模式 16 | UNDURABLE = 1; // 非持久化 17 | DURABLE = 2; // 持久化 18 | }; 19 | 20 | // 消息的属性 21 | message BasicProperties { 22 | string id = 1; // 消息id 23 | DeliveryMode delivery_mode = 2; // 消息传递模式 24 | string routing_key = 3; // 消息的路由模式 25 | }; 26 | 27 | // 消息的综合定义 28 | message Message { 29 | // 消息载荷的定义 30 | message Payload { 31 | BasicProperties properties = 1; // 消息属性 32 | string body = 2; // 消息正文 33 | string vaild = 3; // 消息是否有效 34 | } 35 | // 消息载荷 36 | Payload payload = 1; 37 | // 消息的长度和消息的偏移量,便于解决粘包问题 38 | uint32 offset = 2; 39 | uint32 length = 3; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /MessageQueue/MqCommon/proto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package mq; 4 | 5 | import "msg.proto"; 6 | import "user.proto"; 7 | 8 | // 打开信道 9 | message openChannelRequest { 10 | string rid = 1; // 消息id 11 | string cid = 2; // 信道id 12 | }; 13 | 14 | // 关闭信道 15 | message closeChannelRequest { 16 | string rid = 1; // 消息id 17 | string cid = 2; // 信道id 18 | }; 19 | 20 | // 声明交换机 21 | message declareExchangeRequest { 22 | string rid = 1; // 消息id 23 | string cid = 2; // 信道id 24 | string exchange_name = 3; // 交换机名称 25 | ExchangeType exchange_type = 4; // 队列名称 26 | bool durable = 5; // 持久化标志 27 | bool auto_delete = 6; // 是否自动删除标志 28 | map args = 7; // 其他参数 29 | }; 30 | 31 | // 删除交换机 32 | message deleteExchangeRequest { 33 | string rid = 1; // 消息id 34 | string cid = 2; // 信道id 35 | string exchange_name = 3; // 交换机名称 36 | }; 37 | 38 | // 声明队列 39 | message declareQueueRequest { 40 | string rid = 1; // 消息id 41 | string cid = 2; // 信道id 42 | string queue_name = 3; // 队列名称 43 | bool exclusive = 4; // 是否独占标志 44 | bool durable = 5; // 是否持久化标志 45 | bool auto_delete = 6; // 是否自动删除 46 | map args = 7; // 其他参数 47 | }; 48 | 49 | // 删除队列 50 | message deleteQueueRequest { 51 | string rid = 1; // 消息id 52 | string cid = 2; // 信道id 53 | string queue_name = 3; // 队列名称 54 | }; 55 | 56 | // 交换机-队列绑定 57 | message queueBindRequest { 58 | string rid = 1; // 消息id 59 | string cid = 2; // 信道id 60 | string exchange_name = 3; // 交换机名称 61 | string queue_name = 4; // 队列名称 62 | string binding_key = 5; // 绑定属性 63 | }; 64 | 65 | // 交换机-队列取消绑定 66 | message queueUnBindRequest { 67 | string rid = 1; // 消息id 68 | string cid = 2; // 信道id 69 | string exchange_name = 3; // 交换机名称 70 | string queue_name = 4; // 队列名称 71 | }; 72 | 73 | // 消息的发布 74 | message basicPublishRequest { 75 | string rid = 1; // 消息id 76 | string cid = 2; // 信道id 77 | string exchange_name = 3; // 交换机名称 78 | BasicProperties properties = 4; // 消息属性 79 | string body = 5; // 消息正文 80 | }; 81 | 82 | // 消息的确认 83 | message basicAckRequest { 84 | string rid = 1; // 消息id 85 | string cid = 2; // 信道id 86 | string queue_name = 3; // 队列名称 87 | string message_id = 4; // 消息id 88 | }; 89 | 90 | // 订阅消息 91 | message basicConsumeRequest { 92 | string rid = 1; // 消息id 93 | string cid = 2; // 信道id 94 | string queue_name = 3; // 队列名称 95 | string consumer_tag = 4; // 消费者标识 96 | bool auto_ack = 5; // 自动确认标志 97 | } 98 | 99 | // 订阅的取消 100 | message basicCancelRequest { 101 | string rid = 1; // 消息id 102 | string cid = 2; // 信道id 103 | string queue_name = 3; // 队列名称 104 | string consumer_tag = 4; // 消费者标识 105 | }; 106 | 107 | // 消息的推送 108 | message basicConsumeResponce { 109 | string cid = 1; // 信道id 110 | string consumer_tag = 2; // 消费者标识 111 | string body = 3; // 消息正文 112 | BasicProperties properties = 4; // 消息属性 113 | }; 114 | 115 | // 最常见的响应 116 | message basicCommonResponce { 117 | string rid = 1; // 消息id 118 | string cid = 2; // 信道id 119 | bool ok = 3; // 收到的消息是否正常 120 | UserType user_type = 4; // 用户的类型 121 | }; -------------------------------------------------------------------------------- /MessageQueue/MqCommon/threadpool.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_THRPOOL_H__ 2 | #define __M_THRPOOL_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace mq { 15 | class threadpool { 16 | private: 17 | using func_t = std::function; 18 | 19 | // 线程入口函数,不断的从任务池中取出任务进行执行 20 | void entry() { 21 | // 线程的处理,循环一直处理 22 | while (!_stop) { 23 | std::vector temp_taskpool; 24 | { 25 | std::unique_lock lock(_mutex); 26 | // 等待任务池不为空,或者_stop被置为返回 27 | _cv.wait(lock, [this](){ return _stop || !_taskpool.empty(); }); 28 | // 取出任务执行 29 | temp_taskpool.swap(_taskpool); 30 | } 31 | for (auto& task : temp_taskpool) 32 | task(); 33 | } 34 | } 35 | 36 | public: 37 | using ptr = std::shared_ptr; 38 | 39 | threadpool(int thread_count = 1) : _stop(false) { 40 | for (int i = 0; i < thread_count; i++) 41 | _threads.emplace_back(&threadpool::entry, this); 42 | 43 | } 44 | 45 | // push函数中传入函数及其对应的参数(可变) 46 | // 返回一个future对象,由于future对象我们并不知道其类型是啥,所以需要返回值设置为auto 47 | // push内部将函数封装成一个异步任务(packaged_task),同时使用lambda生成一个可调用对象 48 | // 然后抛入到任务池中,由线程去执行 49 | template 50 | auto push(F&& func, Args&& ...args) -> std::future { 51 | // 1. 将func封装成packaged_task 52 | using return_type = decltype(func(args...)); 53 | auto functor = std::bind(std::forward(func), std::forward(args)...); 54 | auto ptask = std::make_shared>(functor); 55 | std::future fu = ptask->get_future(); 56 | // 2. 将封装好的任务放入到task队列中 57 | { 58 | std::unique_lock lock(_mutex); 59 | auto task = [ptask](){ (*ptask)(); }; 60 | _taskpool.push_back(task); 61 | // 3. 唤醒一个线程去执行 62 | _cv.notify_one(); 63 | } 64 | return fu; 65 | } 66 | 67 | // 等待所有的线程退出 68 | void stop() { 69 | _stop = true; 70 | // 将所有的线程唤醒 71 | _cv.notify_all(); 72 | for (auto& th : _threads) 73 | th.join(); 74 | } 75 | 76 | ~threadpool() { 77 | if (_stop == false) 78 | stop(); 79 | } 80 | private: 81 | std::atomic _stop; // 是否停止标志 82 | std::vector _threads; // 多个线程 83 | std::mutex _mutex; // 锁 84 | std::condition_variable _cv; // 条件变量 85 | std::vector _taskpool; // 任务池 86 | }; 87 | } 88 | 89 | 90 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqCommon/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package mq; 4 | 5 | enum UserType { 6 | RECIVER = 0; // 消息接收用户 7 | PUBLISHER = 1; // 消息发布用户 8 | ADMIN = 2; // 管理员 9 | }; 10 | 11 | message userLogin { 12 | string rid = 1; // 消息id 13 | string cid = 2; // 信道id 14 | string username = 3; // 用户姓名 15 | string password = 4; // 用户密码 16 | bool isRegister = 5; // 是否注册 17 | UserType user_type = 6; // 用户类型 18 | } 19 | 20 | message userLogout { 21 | string rid = 1; // 消息id 22 | string cid = 2; // 信道id 23 | string username = 3; // 用户姓名 24 | UserType user_type = 4; // 用户类型 25 | } 26 | -------------------------------------------------------------------------------- /MessageQueue/MqServer/binding.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_BINDING_H__ 2 | #define __M_BINDING_H__ 3 | 4 | #include "../MqCommon/logger.hpp" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/msg.pb.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace mq { 15 | class Binding { 16 | public: 17 | using ptr = std::shared_ptr; 18 | 19 | std::string exchange_name; // 交换机名称 20 | std::string msgqueue_name; // 队列名称 21 | std::string binding_key; // 绑定键值 22 | 23 | Binding() {} 24 | 25 | Binding(const std::string& ename, const std::string& qname, const std::string key) 26 | : exchange_name(ename), 27 | msgqueue_name(qname), 28 | binding_key(key) 29 | {} 30 | }; 31 | // 一个msgqueue可以找到对应的绑定信息 32 | using MsgQueueBindingMap = std::unordered_map; 33 | // 一个交换机就可以找到对应的所有绑定的队列信息 34 | using BindingMap = std::unordered_map; 35 | 36 | class BindingMapper { 37 | private: 38 | // 持久化数据管理sql语句 39 | #define SQL_DELETE_BM "drop table if exists binding_table;" 40 | #define SQL_INSERT_BM "insert into binding_table values ('%s', '%s', '%s');" 41 | #define SQL_REMOVE_BM "delete from binding_table where exchange_name='%s' and msgqueue_name='%s';" 42 | #define SQL_REMOVE_EXCHANGE_BM "delete from binding_table where exchange_name='%s';" 43 | #define SQL_REMOVE_MSGQUEUE_BM "delete from binding_table where msgqueue_name='%s';" 44 | #define SQL_CREATE_BM "create table if not exists binding_table ( \ 45 | exchange_name varchar(32), \ 46 | msgqueue_name varchar(32), \ 47 | binding_key varchar(128) \ 48 | );" 49 | #define SQL_SELECT_BM "select exchange_name, msgqueue_name, binding_key from binding_table;" 50 | 51 | // 持久化恢复数据持久化回调函数 52 | static int selectCallback(void* args, int numcol, char** row, char** fields) { 53 | BindingMap* result = static_cast(args); 54 | Binding::ptr bp = std::make_shared(row[0], row[1], row[2]); 55 | MsgQueueBindingMap& mqbp = (*result)[bp->exchange_name]; 56 | mqbp[bp->msgqueue_name] = bp; 57 | return 0; 58 | } 59 | 60 | public: 61 | BindingMapper(const std::string& dbfile) 62 | : _sql_helper(dbfile) 63 | { 64 | std::string parent_path = FileHelper::parentDirectory(dbfile); 65 | FileHelper::createDirectory(parent_path); 66 | assert(_sql_helper.open()); 67 | createTable(); 68 | } 69 | 70 | void createTable() { 71 | int ret = _sql_helper.exec(SQL_CREATE_BM, nullptr, nullptr); 72 | if (ret == false) { 73 | ELOG("表格创建失败\n"); 74 | abort(); 75 | } 76 | } 77 | 78 | void removeTable() { 79 | int ret = _sql_helper.exec(SQL_DELETE_BM, nullptr, nullptr); 80 | if (ret == false) { 81 | ELOG("表格删除失败\n"); 82 | abort(); 83 | } 84 | } 85 | 86 | bool insert(Binding::ptr& binding) { 87 | char buff[256]; 88 | int n = snprintf(buff, sizeof(buff) - 1, SQL_INSERT_BM, 89 | (char*)binding->exchange_name.c_str(), 90 | (char*)binding->msgqueue_name.c_str(), 91 | (char*)binding->binding_key.c_str()); 92 | buff[n] = 0; 93 | std::string insert_sql(buff); 94 | return _sql_helper.exec(insert_sql, nullptr, nullptr); 95 | } 96 | 97 | void remove(const std::string& ename, const std::string& qname) { 98 | char buff[256]; 99 | int n = snprintf(buff, sizeof(buff) - 1, SQL_REMOVE_BM, ename.c_str(), qname.c_str()); 100 | buff[n] = 0; 101 | std::string remove_sql(buff); 102 | _sql_helper.exec(remove_sql, nullptr, nullptr); 103 | } 104 | 105 | // 移除绑定关系 106 | void removeExchangeBindings(const std::string& ename) { 107 | char buff[256]; 108 | int n = snprintf(buff, sizeof(buff) - 1, SQL_REMOVE_EXCHANGE_BM, ename.c_str()); 109 | buff[n] = 0; 110 | std::string remove_sql(buff); 111 | _sql_helper.exec(remove_sql, nullptr, nullptr); 112 | } 113 | 114 | void removeMsgQueueBindings(const std::string& qname) { 115 | char buff[256]; 116 | int n = snprintf(buff, sizeof(buff) - 1, SQL_REMOVE_MSGQUEUE_BM, qname.c_str()); 117 | buff[n] = 0; 118 | std::string remove_sql(buff); 119 | _sql_helper.exec(remove_sql, nullptr, nullptr); 120 | } 121 | 122 | BindingMap recovery() { 123 | BindingMap result; 124 | _sql_helper.exec(SQL_SELECT_BM, selectCallback, (void*)(&result)); 125 | return result; 126 | } 127 | 128 | private: 129 | SqliteHelper _sql_helper; 130 | }; 131 | 132 | class BindingManager { 133 | public: 134 | using ptr = std::shared_ptr; 135 | 136 | BindingManager(const std::string& dbfile) 137 | : _mapper(dbfile) 138 | { 139 | _bindings = _mapper.recovery(); 140 | } 141 | 142 | bool bind(const std::string& ename, const std::string& qname, const std::string& key, bool durable) { 143 | std::unique_lock lock(_mutex); 144 | // 需要先检查是否已经绑定 145 | auto eit = _bindings.find(ename); 146 | if (eit != _bindings.end() && eit->second.find(qname) != eit->second.end()) 147 | return true; 148 | // 创建对应的MsgQueueMap 149 | MsgQueueBindingMap& mqbp = _bindings[ename]; 150 | Binding::ptr bp = std::make_shared(ename, qname, key); 151 | if (durable) { 152 | bool ret = _mapper.insert(bp); 153 | if (ret == false) 154 | return false; 155 | } 156 | mqbp.insert(std::make_pair(qname, bp)); 157 | return true; 158 | } 159 | 160 | void unBind(const std::string& ename, const std::string& qname) { 161 | std::unique_lock lock(_mutex); 162 | 163 | // 先查找当前绑定中是否存在这两个信息 164 | auto eit = _bindings.find(ename); 165 | if (eit == _bindings.end()) 166 | return; 167 | auto qit = eit->second.find(qname); 168 | if (qit == eit->second.end()) 169 | return; 170 | // 现在删除 171 | MsgQueueBindingMap& mqbp = _bindings[ename]; 172 | _mapper.remove(ename, qname); 173 | mqbp.erase(qname); 174 | } 175 | 176 | void removeExchangeBindings(const std::string& ename) { 177 | std::unique_lock lock(_mutex); 178 | auto eit = _bindings.find(ename); 179 | if (eit == _bindings.end()) 180 | return; 181 | // 现在遍历mqbp进行删除 182 | _mapper.removeExchangeBindings(ename); 183 | _bindings.erase(ename); 184 | } 185 | 186 | void removeMsgQueueBindings(const std::string& qname) { 187 | std::unique_lock lock(_mutex); 188 | _mapper.removeMsgQueueBindings(qname); 189 | // 开始循环交换机映射的绑定 190 | 191 | for (auto& eit : _bindings) { 192 | // 在每个交换机中寻找与其绑定的消息队列 193 | MsgQueueBindingMap& mqbp = eit.second; 194 | auto qit = mqbp.find(qname); 195 | if (qit == mqbp.end()) 196 | continue; 197 | // // 删除该对应的绑定信息 198 | // std::string ename = eit.first; 199 | // _mapper.remove(ename, qname); 200 | mqbp.erase(qname); 201 | } 202 | 203 | } 204 | 205 | Binding::ptr getBinding(const std::string& ename, const std::string& qname) { 206 | std::unique_lock lock(_mutex); 207 | // 先查找当前绑定中是否存在这两个信息 208 | auto eit = _bindings.find(ename); 209 | if (eit == _bindings.end()) 210 | return Binding::ptr(); 211 | auto qit = eit->second.find(qname); 212 | if (qit == eit->second.end()) 213 | return Binding::ptr(); 214 | return qit->second; 215 | } 216 | 217 | MsgQueueBindingMap getExchangeBindings(const std::string& ename) { 218 | std::unique_lock lock(_mutex); 219 | auto eit = _bindings.find(ename); 220 | if (eit == _bindings.end()) 221 | return MsgQueueBindingMap(); 222 | return eit->second; 223 | } 224 | 225 | size_t size() { 226 | std::unique_lock lock(_mutex); 227 | size_t total = 0; 228 | for (auto eit : _bindings) 229 | total += eit.second.size(); 230 | return total; 231 | } 232 | 233 | bool exists(const std::string& ename, const std::string& qname) { 234 | std::unique_lock lock(_mutex); 235 | // 先查找当前绑定中是否存在这两个信息 236 | auto eit = _bindings.find(ename); 237 | if (eit == _bindings.end()) 238 | return false; 239 | auto qit = eit->second.find(qname); 240 | if (qit == eit->second.end()) 241 | return false; 242 | return true; 243 | } 244 | 245 | void clear() { 246 | std::unique_lock lock(_mutex); 247 | _mapper.removeTable(); 248 | _bindings.clear(); 249 | } 250 | private: 251 | std::mutex _mutex; 252 | BindingMapper _mapper; 253 | BindingMap _bindings; 254 | }; 255 | } 256 | 257 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/broker.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_BROKER_H__ 2 | #define __M_BROKER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../MqThird/include/codec.h" 9 | #include "../MqThird/include/dispatcher.h" 10 | #include "../MqCommon/msg.pb.h" 11 | #include "../MqCommon/proto.pb.h" 12 | #include "../MqCommon/admin.pb.h" 13 | #include "../MqCommon/threadpool.hpp" 14 | #include "../MqCommon/user.pb.h" 15 | #include "host.hpp" 16 | #include "consumer.hpp" 17 | #include "connection.hpp" 18 | #include "users.hpp" 19 | 20 | namespace mq { 21 | 22 | #define DEFAULT_DBFILE "/meta.db" 23 | #define HOST_NAME "MyVirtualHost" 24 | 25 | class BrokerServer { 26 | private: 27 | using MessagePtr = std::shared_ptr; 28 | using UserLoginInfoPtr = std::shared_ptr; 29 | using userLogoutInfoPtr = std::shared_ptr; 30 | using userInfoRequestPtr = std::shared_ptr; 31 | using garbageRecivePtr = std::shared_ptr; 32 | using getExchangeTypeRequestPtr = std::shared_ptr; 33 | 34 | void onConnection(const muduo::net::TcpConnectionPtr& conn) { 35 | 36 | if (conn->connected()) 37 | _connection_manager->newConnection(_virtual_host, _consumer_manager, _codec, conn, _threadpool); 38 | else 39 | _connection_manager->delConnection(conn); 40 | } 41 | // 默认的处理函数 42 | void unUnKnownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp) { 43 | LOG_INFO << "unUnKnownMessage" << message->GetTypeName(); 44 | conn->shutdown(); // 关闭连接 45 | } 46 | 47 | void onGetExchangeType(const muduo::net::TcpConnectionPtr& conn, const getExchangeTypeRequestPtr& message, muduo::Timestamp) { 48 | Exchange::ptr ep = _virtual_host->selectExchange(message->exchange_name()); 49 | getExchangeTypeResponce resp; 50 | resp.set_rid(message->rid()); 51 | resp.set_cid(message->cid()); 52 | if (ep.get() == nullptr) { 53 | resp.set_type(0); 54 | } else { 55 | if (ep->type == ExchangeType::DIRECT) 56 | resp.set_type(1); 57 | else if (ep->type == ExchangeType::FANOUT) 58 | resp.set_type(2); 59 | else 60 | resp.set_type(3); 61 | } 62 | // 发送出去 63 | _codec->send(conn, resp); 64 | } 65 | 66 | void onUserLogin(const muduo::net::TcpConnectionPtr& conn, const UserLoginInfoPtr& message) { 67 | auto ret = _users->login(message->username(), message->password()); 68 | basicCommonResponce resp; 69 | resp.set_ok(ret.first); 70 | resp.set_cid(message->cid()); 71 | resp.set_rid(message->rid()); 72 | // 设置用户的类型 73 | UserType user_type = ret.second == 1 ? mq::RECIVER : mq::PUBLISHER; 74 | if (ret.second == 0) 75 | user_type = mq::ADMIN; 76 | resp.set_user_type(user_type); 77 | _codec->send(conn, resp); 78 | } 79 | 80 | void onUserRegister(const muduo::net::TcpConnectionPtr& conn, const UserLoginInfoPtr& message) { 81 | bool ret = _users->signIn(message->username(), message->password(), message->user_type()); 82 | basicCommonResponce resp; 83 | resp.set_ok(ret); 84 | resp.set_cid(message->cid()); 85 | resp.set_rid(message->rid()); 86 | resp.set_user_type(message->user_type()); 87 | _codec->send(conn, resp); 88 | } 89 | 90 | void onGarbageRecive(const muduo::net::TcpConnectionPtr& conn, const garbageRecivePtr& message, muduo::Timestamp) { 91 | _virtual_host->gc(); 92 | basicCommonResponce resp; 93 | resp.set_cid(message->cid()); 94 | resp.set_rid(message->rid()); 95 | _codec->send(conn, resp); 96 | } 97 | 98 | void onUserLogout(const muduo::net::TcpConnectionPtr& conn, const userLogoutInfoPtr& message, muduo::Timestamp) { 99 | _users->logout(message->username()); 100 | basicCommonResponce resp; 101 | resp.set_ok(true); 102 | resp.set_cid(message->cid()); 103 | resp.set_rid(message->rid()); 104 | resp.set_user_type(message->user_type()); 105 | _codec->send(conn, resp); 106 | } 107 | 108 | void onCheckUser(const muduo::net::TcpConnectionPtr& conn, const UserLoginInfoPtr& message, muduo::Timestamp) { 109 | // 先判断是否进行注册用户 110 | bool isRegister = message->isregister(); 111 | if (!isRegister) 112 | onUserLogin(conn, message); 113 | else 114 | onUserRegister(conn,message); 115 | // 直接在服务器的第一层就拦截用户登陆 116 | // 只有当用户成功登陆才可以继续进行用能使用 117 | } 118 | 119 | void onUserAllInfo(const muduo::net::TcpConnectionPtr& conn, const userInfoRequestPtr& message, muduo::Timestamp) { 120 | userInfoResponce resp; 121 | resp.set_cid(message->cid()); 122 | resp.set_rid(message->rid()); 123 | // 现在从底层将数据获取到 124 | std::string allusers = _users->getAllUsers(); 125 | resp.set_user_infos(allusers); 126 | _codec->send(conn, resp); 127 | } 128 | 129 | // 打开信道 130 | void onOpenChannel(const muduo::net::TcpConnectionPtr& conn, const openChannelRequestPtr& message, muduo::Timestamp) { 131 | Connection::ptr mconn = _connection_manager->getConnection(conn); 132 | if (mconn.get() == nullptr) { 133 | DLOG("打开信道时,没有找到对应的连接\n"); 134 | return; 135 | } 136 | mconn->openChannel(message); 137 | } 138 | 139 | void onCloseChannel(const muduo::net::TcpConnectionPtr& conn, const closeChannelRequestPtr& message, muduo::Timestamp) { 140 | Connection::ptr mconn = _connection_manager->getConnection(conn); 141 | if (mconn.get() == nullptr) { 142 | DLOG("关闭信道时,没有找到对应的连接\n"); 143 | return; 144 | } 145 | mconn->closeChannel(message); 146 | } 147 | 148 | void onDeclareExchange(const muduo::net::TcpConnectionPtr& conn, const declareExchangeRequestPtr& message, muduo::Timestamp) { 149 | Connection::ptr mconn = _connection_manager->getConnection(conn); 150 | if (mconn.get() == nullptr) { 151 | DLOG("声明交换机时,没有找到对应的连接\n"); 152 | conn->shutdown(); 153 | return; 154 | } 155 | Channel::ptr channel = mconn->getChannel(message->cid()); 156 | if (channel.get() == nullptr) { 157 | DLOG("声明交换机时,没有找到对应的信道\n"); 158 | return; 159 | } 160 | channel->declareExchange(message); 161 | } 162 | 163 | void onDeleteExchange(const muduo::net::TcpConnectionPtr& conn, const deleteExchangeRequestPtr& message, muduo::Timestamp) { 164 | Connection::ptr mconn = _connection_manager->getConnection(conn); 165 | if (mconn.get() == nullptr) { 166 | DLOG("关闭交换机时,没有找到对应的连接\n"); 167 | return; 168 | } 169 | Channel::ptr channel = mconn->getChannel(message->cid()); 170 | if (channel.get() == nullptr) { 171 | DLOG("关闭交换机时,没有找到对应的信道\n"); 172 | return; 173 | } 174 | channel->deleteExchange(message); 175 | } 176 | 177 | void onDeclareQueue(const muduo::net::TcpConnectionPtr& conn, const declareQueueRequestPtr& message, muduo::Timestamp) { 178 | Connection::ptr mconn = _connection_manager->getConnection(conn); 179 | if (mconn.get() == nullptr) { 180 | DLOG("声明队列时,没有找到对应的连接\n"); 181 | return; 182 | } 183 | Channel::ptr channel = mconn->getChannel(message->cid()); 184 | if (channel.get() == nullptr) { 185 | DLOG("声明队列时,没有找到对应的信道\n"); 186 | return; 187 | } 188 | channel->declareQueue(message); 189 | } 190 | 191 | void onDeleteQueue(const muduo::net::TcpConnectionPtr& conn, const deleteQueueRequestPtr& message, muduo::Timestamp) { 192 | Connection::ptr mconn = _connection_manager->getConnection(conn); 193 | if (mconn.get() == nullptr) { 194 | DLOG("关闭队列时,没有找到对应的连接\n"); 195 | return; 196 | } 197 | Channel::ptr channel = mconn->getChannel(message->cid()); 198 | if (channel.get() == nullptr) { 199 | DLOG("关闭队列时,没有找到对应的信道\n"); 200 | return; 201 | } 202 | channel->deleteQueue(message); 203 | } 204 | 205 | void onQueueBind(const muduo::net::TcpConnectionPtr& conn, const queueBindRequestPtr& message, muduo::Timestamp) { 206 | Connection::ptr mconn = _connection_manager->getConnection(conn); 207 | if (mconn.get() == nullptr) { 208 | DLOG("绑定队列时,没有找到对应的连接\n"); 209 | return; 210 | } 211 | Channel::ptr channel = mconn->getChannel(message->cid()); 212 | if (channel.get() == nullptr) { 213 | DLOG("绑定队列时,没有找到对应的信道\n"); 214 | return; 215 | } 216 | channel->bind(message); 217 | } 218 | 219 | void onQueueUnBind(const muduo::net::TcpConnectionPtr& conn, const queueUnBindRequestPtr& message, muduo::Timestamp) { 220 | Connection::ptr mconn = _connection_manager->getConnection(conn); 221 | if (mconn.get() == nullptr) { 222 | DLOG("解绑队列时,没有找到对应的连接\n"); 223 | return; 224 | } 225 | Channel::ptr channel = mconn->getChannel(message->cid()); 226 | if (channel.get() == nullptr) { 227 | DLOG("解绑队列时,没有找到对应的信道\n"); 228 | return; 229 | } 230 | channel->unBind(message); 231 | } 232 | 233 | void onBasicPublish(const muduo::net::TcpConnectionPtr& conn, const basicPublishRequestPtr& message, muduo::Timestamp) { 234 | Connection::ptr mconn = _connection_manager->getConnection(conn); 235 | if (mconn.get() == nullptr) { 236 | DLOG("发布消息时,没有找到对应的连接\n"); 237 | return; 238 | } 239 | Channel::ptr channel = mconn->getChannel(message->cid()); 240 | if (channel.get() == nullptr) { 241 | DLOG("发布消息时,没有找到对应的信道\n"); 242 | return; 243 | } 244 | channel->basicPublish(message); 245 | } 246 | 247 | void onBasicAck(const muduo::net::TcpConnectionPtr& conn, const basicAckRequestPtr& message, muduo::Timestamp) { 248 | Connection::ptr mconn = _connection_manager->getConnection(conn); 249 | if (mconn.get() == nullptr) { 250 | DLOG("确认消息时,没有找到对应的连接\n"); 251 | return; 252 | } 253 | Channel::ptr channel = mconn->getChannel(message->cid()); 254 | if (channel.get() == nullptr) { 255 | DLOG("确认消息时,没有找到对应的信道\n"); 256 | return; 257 | } 258 | channel->basicAck(message); 259 | } 260 | 261 | void onBasicConsume(const muduo::net::TcpConnectionPtr& conn, const basicConsumeRequestPtr& message, muduo::Timestamp) { 262 | Connection::ptr mconn = _connection_manager->getConnection(conn); 263 | if (mconn.get() == nullptr) { 264 | DLOG("订阅消息时,没有找到对应的连接\n"); 265 | return; 266 | } 267 | Channel::ptr channel = mconn->getChannel(message->cid()); 268 | if (channel.get() == nullptr) { 269 | DLOG("订阅消息时,没有找到对应的信道\n"); 270 | return; 271 | } 272 | channel->basicConsume(message); 273 | } 274 | 275 | void onBasicCancel(const muduo::net::TcpConnectionPtr& conn, const basicCancelRequestPtr& message, muduo::Timestamp) { 276 | Connection::ptr mconn = _connection_manager->getConnection(conn); 277 | if (mconn.get() == nullptr) { 278 | DLOG("取消订阅时,没有找到对应的连接\n"); 279 | return; 280 | } 281 | Channel::ptr channel = mconn->getChannel(message->cid()); 282 | if (channel.get() == nullptr) { 283 | DLOG("取消订阅时,没有找到对应的信道\n"); 284 | return; 285 | } 286 | channel->basicCancel(message); 287 | } 288 | 289 | 290 | public: 291 | BrokerServer(uint16_t port, const std::string& basedir) 292 | : _server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port), "Server", muduo::net::TcpServer::kReusePort), 293 | _dispathcher(std::bind(&BrokerServer::unUnKnownMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)), 294 | _codec(std::make_shared(std::bind(&ProtobufDispatcher::onProtobufMessage, 295 | &_dispathcher, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))), 296 | _virtual_host(std::make_shared(HOST_NAME, basedir, basedir + DEFAULT_DBFILE)), 297 | _consumer_manager(std::make_shared()), 298 | _connection_manager(std::make_shared()), 299 | _threadpool(std::make_shared()), 300 | _users(std::make_shared(basedir + DEFAULT_DBFILE)) 301 | { 302 | // 恢复历史队列消息 303 | MsgQueueMapper::MsgQueueMap qmap = _virtual_host->allQueue(); 304 | for (auto& q : qmap) 305 | _consumer_manager->initQueueConsumer(q.first); 306 | // 现在注册业务处理请求函数 307 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onOpenChannel, this, 308 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 309 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onCloseChannel, this, 310 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 311 | 312 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onDeclareExchange, this, 313 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 314 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onDeleteExchange, this, 315 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 316 | 317 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onDeclareQueue, this, 318 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 319 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onDeleteQueue, this, 320 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 321 | 322 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onQueueBind, this, 323 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 324 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onQueueUnBind, this, 325 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 326 | 327 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onBasicPublish, this, 328 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 329 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onBasicAck, this, 330 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 331 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onBasicConsume, this, 332 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 333 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onBasicCancel, this, 334 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 335 | 336 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onCheckUser, this, 337 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 338 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onUserLogout, this, 339 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 340 | 341 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onUserAllInfo, this, 342 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 343 | 344 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onGarbageRecive, this, 345 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 346 | 347 | _dispathcher.registerMessageCallback(std::bind(&BrokerServer::onGetExchangeType, this, 348 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 349 | 350 | _server.setMessageCallback(std::bind(&ProtobufCodec::onMessage, _codec.get(), 351 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 352 | _server.setConnectionCallback(std::bind(&BrokerServer::onConnection, this, std::placeholders::_1)); 353 | } 354 | 355 | void start() { 356 | // 服务器开始运行 357 | _server.start(); 358 | // 开始IO监控 359 | _baseloop.loop(); 360 | } 361 | 362 | private: 363 | muduo::net::TcpServer _server; // 服务器对象 364 | muduo::net::EventLoop _baseloop; // 主事件循环器,响应和监听IO事件 365 | ProtobufDispatcher _dispathcher; // 请求分发器对象,需要向分发器中的注册处理函数 366 | ProtobufCodecPtr _codec; // protobuf 协议处理器,针对收到的请求数据进行protobuf协议处理 367 | VirtualHost::ptr _virtual_host; // 虚拟机 368 | ConsumerManager::ptr _consumer_manager; // 消费者管理句柄 369 | ConnectionManager::ptr _connection_manager; // 连接管理句柄 370 | threadpool::ptr _threadpool; // 线程池管理句柄 371 | 372 | UserManager::ptr _users; // 用户管理句柄 373 | }; 374 | 375 | } 376 | 377 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/channel.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_CHANNEL_H__ 2 | #define __M_CHANNEL_H__ 3 | 4 | #include 5 | #include "../MqThird/include/codec.h" 6 | #include "../MqCommon/proto.pb.h" 7 | #include "../MqCommon/msg.pb.h" 8 | #include "../MqCommon/helper.hpp" 9 | #include "../MqCommon/logger.hpp" 10 | #include "../MqCommon/threadpool.hpp" 11 | #include "consumer.hpp" 12 | #include "host.hpp" 13 | #include "route.hpp" 14 | 15 | namespace mq { 16 | using ProtobufCodecPtr = std::shared_ptr; 17 | // 以下请求的智能指针全都是基于proto.pb.h中生成的信息管理类 18 | using openChannelRequestPtr = std::shared_ptr; 19 | using closeChannelRequestPtr = std::shared_ptr; 20 | using declareExchangeRequestPtr = std::shared_ptr; 21 | using deleteExchangeRequestPtr = std::shared_ptr; 22 | using declareQueueRequestPtr = std::shared_ptr; 23 | using deleteQueueRequestPtr = std::shared_ptr; 24 | using queueBindRequestPtr = std::shared_ptr; 25 | using queueUnBindRequestPtr = std::shared_ptr; 26 | using basicPublishRequestPtr = std::shared_ptr; 27 | using basicAckRequestPtr = std::shared_ptr; 28 | using basicCancelRequestPtr = std::shared_ptr; 29 | using basicConsumeResponcePtr = std::shared_ptr; 30 | using basicConsumeRequestPtr = std::shared_ptr; 31 | 32 | class Channel { 33 | private: 34 | // 基础响应,将响应发回给客户端 35 | void basicResponce(bool ok, const std::string& rid, const std::string& cid) { 36 | basicCommonResponce resp; 37 | // 设置响应的各个参数 38 | resp.set_cid(cid); 39 | resp.set_rid(rid); 40 | resp.set_ok(ok); 41 | _codec->send(_conn, resp); 42 | } 43 | 44 | // 使用这个作为回调函数进行消息消费 45 | void consume(const std::string& qname) { 46 | // 1. 取出一个消息 47 | MessagePtr mp = _host->basicConsume(qname); 48 | if (mp.get() == nullptr) { 49 | DLOG("消费消息失败,%s 队列没有可以消费的消息\n", qname.c_str()); 50 | return; 51 | } 52 | // 2. 取出一个消费者 53 | Consumer::ptr cp = _cmp->choose(qname); 54 | if (cp.get() == nullptr) { 55 | DLOG("消费消息失败,%s 队列没有消费者\n", qname.c_str()); 56 | return; 57 | } 58 | // 进行消息消费 59 | cp->callback(cp->tag, mp->mutable_payload()->mutable_properties(), mp->payload().body()); 60 | // 若当前为自动删除,则直接将消息给删除了,否则需要之后手动删除 61 | if (cp->auto_ack) 62 | _host->basicAck(qname, mp->payload().properties().id()); 63 | } 64 | 65 | // 消息处理回调函数 66 | void callback(const std::string& tag, const BasicProperties* bp, const std::string& body) { 67 | basicConsumeResponce resp; 68 | resp.set_body(body); 69 | resp.set_cid(_cid); 70 | resp.set_consumer_tag(tag); 71 | if (bp) { 72 | resp.mutable_properties()->set_id(bp->id()); 73 | resp.mutable_properties()->set_routing_key(bp->routing_key()); 74 | resp.mutable_properties()->set_delivery_mode(bp->delivery_mode()); 75 | } 76 | _codec->send(_conn, resp); 77 | } 78 | 79 | public: 80 | using ptr = std::shared_ptr; 81 | 82 | Channel(const std::string& id, 83 | const VirtualHost::ptr& host, 84 | const ConsumerManager::ptr& cmp, 85 | const ProtobufCodecPtr& codec, 86 | const muduo::net::TcpConnectionPtr conn, 87 | const threadpool::ptr& pool) 88 | : _cid(id), 89 | _conn(conn), 90 | _codec(codec), 91 | _cmp(cmp), 92 | _host(host), 93 | _pool(pool) 94 | {} 95 | 96 | // 交换机声明 97 | void declareExchange(const declareExchangeRequestPtr& req) { 98 | bool ret = _host->declareExchange(req->exchange_name(), req->exchange_type(), 99 | req->durable(), req->auto_delete(), req->args()); 100 | basicResponce(ret, req->rid(), req->cid()); 101 | } 102 | 103 | // 删除交换机 104 | void deleteExchange(const deleteExchangeRequestPtr& req) { 105 | _host->deleteExchange(req->exchange_name()); 106 | basicResponce(true, req->rid(), req->cid()); 107 | } 108 | 109 | // 队列声明 110 | void declareQueue(const declareQueueRequestPtr& req) { 111 | bool ret = _host->declareQueue(req->queue_name(), 112 | req->durable(), req->exclusive(), req->auto_delete(), req->args()); 113 | if (ret == false) 114 | return basicResponce(ret, req->rid(), req->cid()); 115 | _cmp->initQueueConsumer(req->queue_name()); 116 | basicResponce(ret, req->rid(), req->cid()); 117 | } 118 | 119 | // 删除队列 120 | void deleteQueue(const deleteQueueRequestPtr& req) { 121 | _host->deleteQueue(req->queue_name()); 122 | _cmp->destroyQueueConsumer(req->queue_name()); 123 | basicResponce(true, req->rid(), req->cid()); 124 | } 125 | 126 | // 绑定 127 | void bind(const queueBindRequestPtr& req) { 128 | bool ret = _host->bind(req->exchange_name(), req->queue_name(), req->binding_key()); 129 | basicResponce(ret, req->rid(), req->cid()); 130 | } 131 | 132 | // 解绑 133 | void unBind(const queueUnBindRequestPtr& req) { 134 | _host->unBind(req->exchange_name(), req->queue_name()); 135 | basicResponce(true, req->rid(), req->cid()); 136 | } 137 | 138 | // 发布消息 139 | void basicPublish(const basicPublishRequestPtr& req) { 140 | // 取出一个交换机 141 | Exchange::ptr ep = _host->selectExchange(req->exchange_name()); 142 | if (ep.get() == nullptr) 143 | return basicResponce(false, req->rid(), req->cid()); 144 | // 根据获取的交换机找到对应的绑定信息 145 | BasicProperties* bp = nullptr; 146 | std::string routing_key; 147 | if (req->has_properties()) { 148 | bp = req->mutable_properties(); 149 | routing_key = req->properties().routing_key(); 150 | } 151 | 152 | MsgQueueBindingMap mqbm = _host->exchangeBindings(req->exchange_name()); 153 | for (auto& binding : mqbm) { 154 | if (Router::route(ep->type, routing_key, binding.second->binding_key)) { 155 | // 将消息加入到队列中 156 | _host->basicPublish(binding.first, bp, req->body()); 157 | 158 | auto task = std::bind(&Channel::consume, this, binding.first); 159 | _pool->push(task); 160 | } 161 | } 162 | basicResponce(true, req->rid(), req->cid()); 163 | } 164 | 165 | // 确认消息 166 | void basicAck(const basicAckRequestPtr& req) { 167 | _host->basicAck(req->queue_name(), req->message_id()); 168 | basicResponce(true, req->rid(), req->cid()); 169 | } 170 | 171 | // 订阅消息 172 | void basicConsume(const basicConsumeRequestPtr& req) { 173 | // 判断当前队列是否存在 174 | bool ret = _host->existsQueue(req->queue_name()); 175 | if (ret == false) 176 | return basicResponce(false, req->rid(), req->cid()); 177 | 178 | auto cb = std::bind(&Channel::callback, this, std::placeholders::_1, 179 | std::placeholders::_2, std::placeholders::_3); 180 | _consumer = _cmp->create(req->consumer_tag(), req->queue_name(), req->auto_ack(), cb); 181 | if (_consumer.get() == nullptr) 182 | return basicResponce(false, req->rid(), req->cid()); 183 | basicResponce(true, req->rid(), req->cid()); 184 | } 185 | 186 | // 取消订阅 187 | void basicCancel(const basicCancelRequestPtr& req) { 188 | // 取消订阅就是将消费者从消费者管理句柄中删除 189 | _cmp->remove(req->queue_name(), req->consumer_tag()); 190 | basicResponce(true, req->rid(), req->cid()); 191 | } 192 | 193 | ~Channel() { 194 | if (_consumer.get() != nullptr) 195 | _cmp->remove(_consumer->qname, _consumer->tag); 196 | } 197 | private: 198 | std::string _cid; // 信道唯一标识 199 | Consumer::ptr _consumer; // 信道关联的消费者 200 | muduo::net::TcpConnectionPtr _conn; // 信道关联的连接 201 | ProtobufCodecPtr _codec; // 协议处理器,protobuf协议处理句柄 202 | ConsumerManager::ptr _cmp; // 消费者管理句柄 203 | VirtualHost::ptr _host; // 虚拟机 204 | threadpool::ptr _pool; // 线程池 205 | }; 206 | 207 | class ChannelManager { 208 | public: 209 | using ptr = std::shared_ptr; 210 | 211 | ChannelManager() { 212 | ILOG("new Channel %p\n", this); 213 | } 214 | 215 | bool openChannel(const std::string& cid, 216 | const VirtualHost::ptr& host, 217 | const ConsumerManager::ptr& cmp, 218 | const ProtobufCodecPtr& codec, 219 | const muduo::net::TcpConnectionPtr conn, 220 | const threadpool::ptr& pool) { 221 | std::unique_lock lock(_mutex); 222 | auto it = _channels.find(cid); 223 | if (it != _channels.end()) 224 | return false; 225 | Channel::ptr channel = std::make_shared(cid, host, cmp, codec, conn, pool); 226 | _channels[cid] = channel; 227 | return true; 228 | } 229 | 230 | void closeChannel(const std::string& cid) { 231 | std::unique_lock lock(_mutex); 232 | _channels.erase(cid); 233 | } 234 | 235 | Channel::ptr getChannel(const std::string& cid) { 236 | std::unique_lock lock(_mutex); 237 | auto it = _channels.find(cid); 238 | if (it == _channels.end()) 239 | return Channel::ptr(); 240 | return it->second; 241 | } 242 | 243 | ~ChannelManager() { 244 | ILOG("del Channel %p\n", this); 245 | } 246 | 247 | private: 248 | std::mutex _mutex; 249 | std::unordered_map _channels; 250 | }; 251 | } 252 | 253 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/connection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_CONNECTION_H__ 2 | #define __M_CONNECTION_H__ 3 | #include "channel.hpp" 4 | 5 | namespace mq { 6 | class Connection { 7 | private: 8 | void basicResponce(bool ok, const std::string& rid, const std::string& cid) { 9 | basicCommonResponce resp; 10 | resp.set_cid(cid); 11 | resp.set_rid(rid); 12 | resp.set_ok(ok); 13 | _codec->send(_conn, resp); 14 | } 15 | 16 | public: 17 | using ptr = std::shared_ptr; 18 | 19 | Connection(const VirtualHost::ptr& host, 20 | const ConsumerManager::ptr& cmp, 21 | const ProtobufCodecPtr& codec, 22 | const muduo::net::TcpConnectionPtr conn, 23 | const threadpool::ptr& pool) 24 | : _conn(conn), 25 | _codec(codec), 26 | _cmp(cmp), 27 | _host(host), 28 | _pool(pool), 29 | _channels(std::make_shared()) 30 | {} 31 | 32 | void openChannel(const openChannelRequestPtr& req) { 33 | // 先检查是否存在 34 | bool ret = _channels->openChannel(req->cid(), _host, _cmp, _codec, _conn, _pool); 35 | if (ret == false) { 36 | DLOG("信道已经存在,信道ID重复\n"); 37 | return this->basicResponce(false, req->rid(), req->cid()); 38 | } 39 | ILOG("%s 信道创建成功\n", req->cid().c_str()); 40 | this->basicResponce(true, req->rid(), req->cid()); 41 | } 42 | 43 | void closeChannel(const closeChannelRequestPtr& req) { 44 | _channels->closeChannel(req->cid()); 45 | this->basicResponce(true, req->rid(), req->cid()); 46 | } 47 | 48 | Channel::ptr getChannel(const std::string& cid) { 49 | return _channels->getChannel(cid); 50 | } 51 | 52 | ~Connection() {} 53 | 54 | private: 55 | // 一个连接模块处理多个信道,一个信道处理一个消费者 56 | muduo::net::TcpConnectionPtr _conn; // 信道关联的连接 57 | ProtobufCodecPtr _codec; //协议处理器,protobuf协议处理句柄 58 | ConsumerManager::ptr _cmp; // 消费者管理句柄 59 | VirtualHost::ptr _host; // 虚拟机 60 | threadpool::ptr _pool; // 线程池 61 | ChannelManager::ptr _channels; // 管理多个信道的句柄 62 | }; 63 | 64 | class ConnectionManager { 65 | public: 66 | using ptr = std::shared_ptr; 67 | 68 | ConnectionManager() {} 69 | 70 | void newConnection(const VirtualHost::ptr& host, 71 | const ConsumerManager::ptr& cmp, 72 | const ProtobufCodecPtr& codec, 73 | const muduo::net::TcpConnectionPtr conn, 74 | const threadpool::ptr& pool) { 75 | std::unique_lock lock(_mutex); 76 | auto it = _conns.find(conn); 77 | if (it != _conns.end()) 78 | return; 79 | Connection::ptr connection = std::make_shared(host, cmp, codec, conn, pool); 80 | _conns[conn] = connection; 81 | } 82 | 83 | void delConnection(const muduo::net::TcpConnectionPtr conn) { 84 | std::unique_lock lock(_mutex); 85 | _conns.erase(conn); 86 | } 87 | 88 | Connection::ptr getConnection(const muduo::net::TcpConnectionPtr conn) { 89 | std::unique_lock lock(_mutex); 90 | auto it = _conns.find(conn); 91 | if (it == _conns.end()) 92 | return Connection::ptr(); 93 | return it->second; 94 | } 95 | private: 96 | // 用于管理多个连接 97 | std::mutex _mutex; 98 | std::unordered_map _conns; // 记录muduo连接与server端连接的映射 99 | }; 100 | } 101 | 102 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/consumer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_CONSUMER_H__ 2 | #define __M_CONSUMER_H__ 3 | 4 | #include "../MqCommon/msg.pb.h" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/logger.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace mq { 15 | using ConsumerCallback = std::function; 16 | 17 | struct Consumer { 18 | using ptr = std::shared_ptr; 19 | 20 | std::string tag; // 消费者标识 21 | std::string qname; // 消费者绑定队列名称 22 | bool auto_ack; // 是否自动确认 23 | ConsumerCallback callback; // 回调函数 24 | 25 | Consumer() { 26 | ILOG("new Consumer %p\n", this); 27 | } 28 | 29 | Consumer(const std::string& ctag, const std::string& queue_name, bool ack, const ConsumerCallback& cb) 30 | : tag(ctag), 31 | qname(queue_name), 32 | auto_ack(ack), 33 | callback(cb) 34 | { 35 | ILOG("new Consumer %p\n", this); 36 | } 37 | 38 | ~Consumer() { 39 | ILOG("del Consumer %p\n", this); 40 | } 41 | }; 42 | 43 | class QueueConsumer { 44 | public: 45 | using ptr = std::shared_ptr; 46 | 47 | QueueConsumer(const std::string qname) 48 | : _qname(qname), 49 | _rr_seq(0) 50 | {} 51 | 52 | // 队列新增一个消费者对象 53 | Consumer::ptr create(const std::string& ctag, const std::string& queue_name, bool ack, const ConsumerCallback& cb) { 54 | std::unique_lock lock(_mutex); 55 | // 先遍历查找当前是否已经存在 56 | for (auto& consumer : _consumers) { 57 | // 若已经存在则直接返回一个空的指针 58 | if (consumer->tag == ctag) 59 | return Consumer::ptr(); 60 | } 61 | // 构造对象 62 | Consumer::ptr consumer = std::make_shared(ctag, queue_name, ack, cb); 63 | _consumers.push_back(consumer); 64 | return consumer; 65 | } 66 | 67 | // 从队列中移除一个消费者对象 68 | void remove(const std::string& ctag) { 69 | std::unique_lock lock(_mutex); 70 | for (auto it = _consumers.begin(); it != _consumers.end(); ++it) { 71 | // 找到对应的元素然后删除 72 | if ((*it)->tag == ctag) { 73 | _consumers.erase(it); 74 | return; 75 | } 76 | } 77 | } 78 | 79 | Consumer::ptr choose() { 80 | std::unique_lock lock(_mutex); 81 | // 若没有消费者则直接返回 82 | if (_consumers.empty()) 83 | return Consumer::ptr(); 84 | // 轮转选取出一个消费者消费消息 85 | int index = _rr_seq % _consumers.size(); 86 | _rr_seq++; 87 | return _consumers[index]; 88 | } 89 | 90 | bool exists(const std::string& ctag) { 91 | std::unique_lock lock(_mutex); 92 | // 循环遍历每个用户 93 | for (auto& consumer : _consumers) { 94 | if (consumer->tag == ctag) 95 | return true; 96 | } 97 | return false; 98 | } 99 | 100 | void clear() { 101 | std::unique_lock lock(_mutex); 102 | _rr_seq = 0; 103 | _consumers.clear(); 104 | } 105 | 106 | bool empty() { 107 | std::unique_lock lock(_mutex); 108 | return _consumers.empty(); 109 | } 110 | 111 | 112 | private: 113 | std::mutex _mutex; // 锁 114 | std::string _qname; // 队列名称 115 | uint64_t _rr_seq; // 轮转序号 116 | std::vector _consumers; // 消费者管理 117 | }; 118 | 119 | 120 | class ConsumerManager { 121 | public: 122 | using ptr = std::shared_ptr; 123 | 124 | ConsumerManager() { 125 | } 126 | 127 | void initQueueConsumer(const std::string& qname) { 128 | std::unique_lock lock(_mutex); 129 | // 查找当前管理的队列中是否已经存在 130 | auto it = _qconsumers.find(qname); 131 | if (it != _qconsumers.end()) 132 | return; 133 | QueueConsumer::ptr qcp = std::make_shared(qname); 134 | _qconsumers[qname] = qcp; 135 | } 136 | 137 | void destroyQueueConsumer(const std::string& qname) { 138 | std::unique_lock lock(_mutex); 139 | auto it = _qconsumers.find(qname); 140 | // 找不到直接退出 141 | if (it == _qconsumers.end()) 142 | return; 143 | _qconsumers.erase(qname); 144 | } 145 | 146 | Consumer::ptr create(const std::string& ctag, const std::string& qname, bool ack, const ConsumerCallback& cb) { 147 | QueueConsumer::ptr qcp; 148 | { 149 | std::unique_lock lock(_mutex); 150 | auto it = _qconsumers.find(qname); 151 | if (it == _qconsumers.end()) { 152 | DLOG("没有找到队列: %s 的管理句柄\n", qname.c_str()); 153 | return Consumer::ptr(); 154 | } 155 | qcp = it->second; 156 | } 157 | return qcp->create(ctag, qname, ack, cb); 158 | } 159 | 160 | void remove(const std::string& qname, const std::string& ctag) { 161 | QueueConsumer::ptr qcp; 162 | { 163 | std::unique_lock lock(_mutex); 164 | auto it = _qconsumers.find(qname); 165 | if (it == _qconsumers.end()) { 166 | DLOG("没有找到队列: %s 的管理句柄\n", qname.c_str()); 167 | return; 168 | } 169 | qcp = it->second; 170 | } 171 | qcp->remove(ctag); 172 | } 173 | 174 | Consumer::ptr choose(const std::string& qname) { 175 | QueueConsumer::ptr qcp; 176 | { 177 | std::unique_lock lock(_mutex); 178 | auto it = _qconsumers.find(qname); 179 | if (it == _qconsumers.end()) { 180 | DLOG("没有找到队列: %s 的管理句柄\n", qname.c_str()); 181 | return Consumer::ptr(); 182 | } 183 | qcp = it->second; 184 | } 185 | return qcp->choose(); 186 | } 187 | 188 | bool empty(const std::string& qname) { 189 | QueueConsumer::ptr qcp; 190 | { 191 | std::unique_lock lock(_mutex); 192 | auto it = _qconsumers.find(qname); 193 | if (it == _qconsumers.end()) { 194 | DLOG("没有找到队列: %s 的管理句柄\n", qname.c_str()); 195 | return false; 196 | } 197 | qcp = it->second; 198 | } 199 | return qcp->empty(); 200 | } 201 | 202 | bool exists(const std::string& qname, const std::string& ctag) { 203 | QueueConsumer::ptr qcp; 204 | { 205 | std::unique_lock lock(_mutex); 206 | auto it = _qconsumers.find(qname); 207 | if (it == _qconsumers.end()) { 208 | DLOG("没有找到队列: %s 的管理句柄\n", qname.c_str()); 209 | return false; 210 | } 211 | qcp = it->second; 212 | } 213 | return qcp->exists(ctag); 214 | } 215 | 216 | void clear() { 217 | std::unique_lock lock(_mutex); 218 | _qconsumers.clear(); 219 | } 220 | 221 | ~ConsumerManager() { 222 | } 223 | private: 224 | std::mutex _mutex; 225 | std::unordered_map _qconsumers; 226 | }; 227 | } 228 | 229 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/data/meta.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqServer/data/meta.db -------------------------------------------------------------------------------- /MessageQueue/MqServer/exchange.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_EXCHANGE_H__ 2 | #define __M_EXCHANGE_H__ 3 | 4 | #include "../MqCommon/logger.hpp" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/msg.pb.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace mq { 16 | // 交换机类 17 | struct Exchange { 18 | using ptr = std::shared_ptr; 19 | 20 | std::string name; // 交换机名称 21 | ExchangeType type; // 交换机类型 22 | bool durable; // 是否继续持久化管理 23 | bool auto_delete; // 是否自动删除 24 | google::protobuf::Map args; // 交换机的其他参数 25 | 26 | Exchange() {} 27 | 28 | Exchange(const std::string& ename, ExchangeType etype, 29 | bool edurable, 30 | bool eauto_delete, 31 | const google::protobuf::Map& eargs) 32 | : name(ename), 33 | type(etype), 34 | durable(edurable), 35 | auto_delete(eauto_delete), 36 | args(eargs) 37 | {} 38 | 39 | // 设置args中的参数,类型为:"key=value&key=value....",相当于将数据反序列化 40 | void setArgs(const std::string& args_str) { 41 | if (args_str.empty()) 42 | return; 43 | std::vector kvs; 44 | StrHelper::split(args_str, "&", kvs); 45 | for (auto& kv : kvs) { 46 | // 现在将key,value放入到map中 47 | size_t pos = kv.find('='); 48 | std::string key = kv.substr(0, pos); 49 | std::string value = kv.substr(pos + 1); 50 | args[key] = value; 51 | } 52 | } 53 | 54 | // 将数据序列化 55 | std::string getArgs() { 56 | std::string result; 57 | for (auto& it : args) { 58 | std::string kv = it.first + "=" + it.second + "&"; 59 | result += kv; 60 | } 61 | return result; 62 | } 63 | }; 64 | 65 | // 交换机持久化管理类,数据存储在sqlite数据库中 66 | class ExchangeMapper { 67 | private: 68 | // 对应的sql语句 69 | #define SQL_DELETE_EM "drop table if exists exchange_table;" 70 | #define SQL_INSERT_EM "insert into exchange_table values ('%s', %d, %d, %d, '%s');" 71 | #define SQL_REMOVE_EM "delete from exchange_table where name=" 72 | #define SQL_CREATE_EM "create table if not exists exchange_table ( \ 73 | name varchar(32) primary key, \ 74 | type int, \ 75 | durable int, \ 76 | auto_delete int, \ 77 | args varchar(128) \ 78 | );" 79 | #define SQL_SELECT_EM "select name, type, durable, auto_delete, args from exchange_table;" 80 | 81 | // 持久化的交换机恢复数据时的回调函数 82 | static int selectCallback(void* args, int numcol, char** row, char** fields) { 83 | ExchangeMap* exchange_map = static_cast(args); 84 | Exchange::ptr exchange = std::make_shared(); 85 | exchange->name = row[0]; 86 | exchange->type = (ExchangeType)std::stoi(row[1]); 87 | exchange->durable = (bool)std::stoi(row[2]); 88 | exchange->auto_delete = (bool)std::stoi(row[3]); 89 | if (row[4]) exchange->setArgs(row[4]); 90 | exchange_map->insert(std::make_pair(exchange->name, exchange)); 91 | 92 | return 0; 93 | } 94 | public: 95 | using ExchangeMap = std::unordered_map; 96 | 97 | ExchangeMapper(const std::string& dbfile) 98 | : _sql_helper(dbfile) 99 | { 100 | // 先获取dbfile上级文件路径 101 | std::string parent_path = FileHelper::parentDirectory(dbfile); 102 | FileHelper::createDirectory(parent_path); 103 | // 将数据库打开 104 | assert(_sql_helper.open()); 105 | createTable(); 106 | } 107 | 108 | void createTable() { 109 | int ret = _sql_helper.exec(SQL_CREATE_EM, nullptr, nullptr); 110 | if (ret == false) { 111 | ELOG("表格创建失败\n"); 112 | abort(); 113 | } 114 | } 115 | 116 | void removeTable() { 117 | // 删除表格 118 | int ret = _sql_helper.exec(SQL_DELETE_EM, nullptr, nullptr); 119 | if (ret == false) { 120 | ELOG("表格删除失败\n"); 121 | abort(); 122 | } 123 | } 124 | 125 | bool insert(const Exchange::ptr& exchange) { 126 | char buff[256]; 127 | // 向sql语句中写入相关参数 128 | int n = snprintf(buff, sizeof(buff) - 1, SQL_INSERT_EM, 129 | (char*)exchange->name.c_str(), 130 | exchange->type, 131 | exchange->durable, 132 | exchange->auto_delete, 133 | (char*)exchange->getArgs().c_str() 134 | ); 135 | buff[n] = 0; 136 | std::string cmd(buff); 137 | cmd += ";"; 138 | return _sql_helper.exec(cmd, nullptr, nullptr); 139 | } 140 | 141 | void remove(const std::string& name) { 142 | std::stringstream ss; 143 | ss << SQL_REMOVE_EM << "'" << name << "'" << ";"; 144 | int ret = _sql_helper.exec(ss.str(), nullptr, nullptr); 145 | if (ret == false) 146 | ELOG("删除交换机数据失败\n"); 147 | } 148 | 149 | ExchangeMap recovery() { 150 | ExchangeMap result; 151 | int ret = _sql_helper.exec(SQL_SELECT_EM, selectCallback, (void*)(&result)); 152 | return result; 153 | } 154 | private: 155 | SqliteHelper _sql_helper; 156 | }; 157 | 158 | // 交换机管理类 159 | class ExchangeManager { 160 | public: 161 | using ptr = std::shared_ptr; 162 | 163 | ExchangeManager(const std::string& dbfile) 164 | : _mapper(dbfile) 165 | { 166 | // 从底层数据库中直接恢复数据 167 | _exchanges = _mapper.recovery(); 168 | } 169 | 170 | // 声明交换机,增加一个交换机 171 | bool declareExchange(const std::string& name, ExchangeType type, bool durable, 172 | bool auto_delete, const google::protobuf::Map& args) { 173 | // 需要先加锁 174 | std::unique_lock lock(_mutex); 175 | // 判断当前需要插入的数据是否已经存在,若存在则我们不需要插入 176 | auto it = _exchanges.find(name); 177 | if (it != _exchanges.end()) 178 | return true; 179 | Exchange::ptr exchange = std::make_shared(name, type, durable, auto_delete, args); 180 | // 判断当前的数据是否需要持久化处理 181 | if (durable == true) { 182 | // 若需要持久化则直接交换机信息放入到持久化管理类中 183 | int ret = _mapper.insert(exchange); 184 | if (ret == false) 185 | return false; 186 | } 187 | _exchanges[name] = exchange; 188 | return true; 189 | } 190 | 191 | // 查找一个交换机 192 | Exchange::ptr selectExchange(const std::string& name) { 193 | std::unique_lock lock(_mutex); 194 | auto it = _exchanges.find(name); 195 | // 当没有找到时直接返回null 196 | if (it == _exchanges.end()) 197 | return std::make_shared(); 198 | return it->second; 199 | } 200 | 201 | // 删除交换机 202 | void deleteExchange(const std::string& name) { 203 | std::unique_lock lock(_mutex); 204 | auto it = _exchanges.find(name); 205 | // 若当前的数据中不存在对应的交换机的时候,直接返回 206 | if (it == _exchanges.end()) 207 | return; 208 | // 删除数据需要删除交换机存储和持久化交换机管理 209 | if (it->second->durable) 210 | _mapper.remove(it->first); 211 | _exchanges.erase(it->first); 212 | } 213 | 214 | bool exists(const std::string& name) { 215 | std::unique_lock lock(_mutex); 216 | auto it = _exchanges.find(name); 217 | if (it == _exchanges.end()) 218 | return false; 219 | else 220 | return true; 221 | } 222 | 223 | size_t size() { 224 | std::unique_lock lock(_mutex); 225 | return _exchanges.size(); 226 | } 227 | 228 | void clear() { 229 | std::unique_lock lock(_mutex); 230 | // 删除持久化数据管理中的表格 231 | _mapper.removeTable(); 232 | _exchanges.clear(); 233 | } 234 | private: 235 | std::mutex _mutex; // 防止出现线程安全问题 236 | ExchangeMapper _mapper; // 交换机持久化数据管理 237 | std::unordered_map _exchanges; // 所有的交换机及其对应的名称 238 | }; 239 | } 240 | 241 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/host.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_HOST_H__ 2 | #define __M_HOST_H__ 3 | 4 | #include 5 | #include "exchange.hpp" 6 | #include "message.hpp" 7 | #include "queue.hpp" 8 | #include "binding.hpp" 9 | 10 | namespace mq { 11 | 12 | class VirtualHost { 13 | public: 14 | using ptr = std::shared_ptr; 15 | 16 | VirtualHost(const std::string& hname, const std::string& basedir, const std::string& dbfile) 17 | : _host_name(hname), 18 | _emp(std::make_shared(dbfile)), 19 | _mmp(std::make_shared(basedir)), 20 | _bmp(std::make_shared(dbfile)), 21 | _mqmp(std::make_shared(dbfile)) 22 | { 23 | // 遍历队列恢复历史消息 24 | MsgQueueMapper::MsgQueueMap mqp = _mqmp->allQueue(); 25 | for (auto& q : mqp) 26 | _mmp->initQueueMessage(q.first); 27 | } 28 | 29 | MsgQueueMapper::MsgQueueMap allQueue() { 30 | return _mqmp->allQueue(); 31 | } 32 | 33 | bool declareExchange(const std::string& ename, ExchangeType etype, bool edurable, 34 | bool eauto_delete, const google::protobuf::Map& eargs) { 35 | return _emp->declareExchange(ename, etype, edurable, eauto_delete, eargs); 36 | } 37 | 38 | void deleteExchange(const std::string& ename) { 39 | // 删除一个交换机,同时需要删除一个交换机的绑定消息 40 | _bmp->removeExchangeBindings(ename); 41 | _emp->deleteExchange(ename); 42 | } 43 | 44 | bool declareQueue(const std::string& msg_name, bool msg_durable, 45 | bool msg_exclusive, bool msg_auto_delete, 46 | const google::protobuf::Map& msg_args) { 47 | // 声明一个队列,现在消息管理中将队列进行初始化 48 | _mmp->initQueueMessage(msg_name); 49 | return _mqmp->declareQueue(msg_name, msg_durable, msg_exclusive, msg_auto_delete, msg_args); 50 | } 51 | 52 | void deleteQueue(const std::string& qname) { 53 | // 删除一个队列,需要将和队列所有有关的数据都删除掉 54 | _bmp->removeMsgQueueBindings(qname); 55 | _mmp->destoryQueueMessahe(qname); 56 | _mqmp->deleteQueue(qname); 57 | } 58 | 59 | MsgQueueBindingMap exchangeBindings(const std::string& ename) { 60 | // 获取交换机的绑定信息 61 | return _bmp->getExchangeBindings(ename); 62 | } 63 | 64 | bool basicPublish(const std::string& qname, const BasicProperties* bp, const std::string& body) { 65 | // 增加一条消息 66 | MsgQueue::ptr mqp = _mqmp->selectQueue(qname); 67 | if (mqp.get() == nullptr) { 68 | DLOG("需要增加消息的队列不存在,队列: %s\n", qname.c_str()); 69 | return false; 70 | } 71 | return _mmp->insert(qname, bp, body, mqp->durable); 72 | } 73 | 74 | void basicAck(const std::string& qname, const std::string& msg_id) { 75 | return _mmp->ack(qname, msg_id); 76 | } 77 | 78 | // 获取一个队首消息,用于消费 79 | MessagePtr basicConsume(const std::string& qname) { 80 | return _mmp->front(qname); 81 | } 82 | 83 | bool bind(const std::string& ename, const std::string& qname, const std::string& key) { 84 | // 绑定前先找到对应的交换机和队列 85 | MsgQueue::ptr mqp = _mqmp->selectQueue(qname); 86 | if (mqp.get() == nullptr) { 87 | DLOG("当前队列不存在,队列: %s\n", qname.c_str()); 88 | return false; 89 | } 90 | Exchange::ptr ep = _emp->selectExchange(ename); 91 | if (ep.get() == nullptr) { 92 | DLOG("当前交换机不存在,交换机: %s\n", ename.c_str()); 93 | return false; 94 | } 95 | return _bmp->bind(ename, qname, key, ep->durable & mqp->durable); 96 | } 97 | 98 | void gc() { 99 | _mmp->gc(); 100 | } 101 | 102 | void unBind(const std::string& ename, const std::string& qname) { 103 | return _bmp->unBind(ename, qname); 104 | } 105 | 106 | bool existsExchange(const std::string& ename) { 107 | return _emp->exists(ename); 108 | } 109 | 110 | bool existsQueue(const std::string& qname) { 111 | return _mqmp->exists(qname); 112 | } 113 | 114 | bool existsBinding(const std::string& ename, const std::string& qname) { 115 | return _bmp->exists(ename, qname); 116 | } 117 | 118 | Exchange::ptr selectExchange(const std::string& ename) { 119 | return _emp->selectExchange(ename); 120 | } 121 | 122 | void clear() { 123 | _emp->clear(); 124 | _mmp->clear(); 125 | _bmp->clear(); 126 | _mqmp->clear(); 127 | } 128 | 129 | private: 130 | std::string _host_name; 131 | ExchangeManager::ptr _emp; // 交换机管理句柄 132 | MessageManager::ptr _mmp; // 消息管理句柄 133 | BindingManager::ptr _bmp; // 绑定管理句柄 134 | MsgQueueManager::ptr _mqmp; // 队列管理句柄 135 | }; 136 | 137 | } 138 | 139 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/makefile: -------------------------------------------------------------------------------- 1 | .PHONY: server 2 | LFLAG= -lprotobuf -lsqlite3 -pthread -lmuduo_net -lmuduo_base -lz -g 3 | server:server.cc ../MqCommon/msg.pb.cc ../MqCommon/proto.pb.cc ../MqThird/include/codec.cc ../MqCommon/user.pb.cc ../MqCommon/admin.pb.cc 4 | g++ -g -std=c++11 $^ -o $@ $(LFLAG) 5 | .PHONY:clean 6 | clean: 7 | rm -f server -------------------------------------------------------------------------------- /MessageQueue/MqServer/message.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_MESSAGE_H__ 2 | #define __M_MESSAGE_H__ 3 | 4 | #include "../MqCommon/logger.hpp" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/msg.pb.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace mq { 14 | // 存储数据文件的后缀 15 | #define DATAFILE_SUBFIX ".mqd" 16 | #define TEMPFILE_SUBFIX ".mqd.tmp" 17 | 18 | using MessagePtr = std::shared_ptr; 19 | 20 | class MessageMapper { 21 | private: 22 | bool insert(MessagePtr& msg, const std::string& filename) { 23 | FileHelper helper(filename); 24 | // 将数据序列化 25 | std::string body = msg->payload().SerializeAsString(); 26 | size_t offset; 27 | offset = helper.size(); 28 | // 先写入数据的长度,8字节长度,然后在写入消息 29 | size_t msg_size = body.size(); 30 | bool ret = helper.write((char*)(&msg_size), offset, sizeof(size_t)); 31 | if (ret == false) { 32 | ELOG("写入数据长度失败\n"); 33 | return false; 34 | } 35 | // 将数据存放到适当的位置 36 | ret = helper.write(body.c_str(), offset + sizeof(size_t), body.size()); 37 | if (ret == false) { 38 | ELOG("写入数据失败\n"); 39 | return false; 40 | } 41 | // 更新数据中存储的位置,以及数据的长度 42 | msg->set_offset(offset + sizeof(size_t)); 43 | msg->set_length(body.size()); 44 | return true; 45 | } 46 | 47 | // 从文件中加载之前存储的数据 48 | bool load_data(std::list& result) { 49 | // 先将文件打开,然后逐一从文件中取出数据 50 | FileHelper helper(_datafile); 51 | size_t offset = 0; 52 | size_t filesize = helper.size(); 53 | while (offset < filesize) { 54 | // 从文件中读出数据 55 | bool ret; 56 | size_t length = 0; 57 | ret = helper.read((char*)(&length), offset, sizeof(size_t)); 58 | if (ret == false) { 59 | ELOG("读取数据长度失败\n"); 60 | return false; 61 | } 62 | offset += sizeof(size_t); 63 | std::string body(length, '\0'); 64 | ret = helper.read((char*)(&body[0]), offset, length); 65 | if (ret == false) { 66 | ELOG("读取数据失败\n"); 67 | return false; 68 | } 69 | MessagePtr msgp = std::make_shared(); 70 | // 对数据载荷进行反序列化 71 | msgp->mutable_payload()->ParseFromString(body); 72 | offset += length; 73 | if (msgp->payload().vaild() == "0") { 74 | DLOG("加载到无效数据: %s\n", msgp->payload().body().c_str()); 75 | continue; 76 | } 77 | result.emplace_back(msgp); 78 | } 79 | return true; 80 | } 81 | 82 | bool createMsgFile() { 83 | // 只有当当前文件不存在的时候才创建,否则会导致文件被重新刷新丢失数据 84 | if (FileHelper(_datafile).exists() == true) 85 | return true; 86 | bool ret = FileHelper::createFile(_datafile); 87 | if (ret == false) { 88 | ELOG("创建 %s 文件失败\n", _datafile.c_str()); 89 | return false; 90 | } 91 | return true; 92 | } 93 | 94 | public: 95 | MessageMapper(const std::string& databasedir, const std::string& qname) 96 | : _qname(qname) 97 | { 98 | std::string basedir(databasedir); 99 | if (basedir.back() != '/') 100 | basedir += '/'; 101 | _datafile = basedir + _qname + DATAFILE_SUBFIX; 102 | _tempfile = basedir + _qname + TEMPFILE_SUBFIX; 103 | // 只有当当前目录不存在的时候才创建对应的目录 104 | // DLOG("当前目录为: %s\n", basedir.c_str()); 105 | if (FileHelper(basedir).exists() == false) 106 | assert(FileHelper::createDirectory(basedir)); 107 | assert(this->createMsgFile()); 108 | } 109 | 110 | bool removeMsgFile() { 111 | bool ret = FileHelper::removeFile(_datafile); 112 | if (ret == false) { 113 | ELOG("移除 %s 文件失败\n", _datafile.c_str()); 114 | return false; 115 | } 116 | return true; 117 | } 118 | 119 | bool insert(MessagePtr& msg) { 120 | return this->insert(msg, _datafile); 121 | } 122 | 123 | bool remove(MessagePtr& msg) { 124 | // 将数据从文件中删除,删除数据就是将数据的有效位置设置为"0" 125 | msg->mutable_payload()->set_vaild("0"); 126 | std::string body = msg->payload().SerializeAsString(); 127 | if (body.size() != msg->length()) { 128 | ELOG("删除数据失败\n"); 129 | return false; 130 | } 131 | // 现在将数据重新写入文件原来的位置 132 | FileHelper helper(_datafile); 133 | bool ret = helper.write(body.c_str(), msg->offset(), body.size()); 134 | if (ret == false) { 135 | ELOG("覆盖原来数据失败\n"); 136 | return false; 137 | } 138 | return true; 139 | } 140 | 141 | // 对我们的数据进行垃圾回收 142 | std::list gc() { 143 | // 1. 先加载数据,拿到有效的数据 144 | std::list result; 145 | bool ret = this->load_data(result); 146 | if (ret == false) { 147 | ELOG("加载数据失败\n"); 148 | return result; 149 | } 150 | // 2. 将有效的数据存放到临时文件中 151 | // 先创建临时文件 152 | FileHelper::createFile(_tempfile); 153 | for (auto& msg : result) { 154 | ret = this->insert(msg, _tempfile); 155 | if (ret == false) { 156 | ELOG("插入数据失败\n"); 157 | return result; 158 | } 159 | } 160 | // 3. 删除源文件 161 | ret = FileHelper::removeFile(_datafile); 162 | if (ret == false) { 163 | ELOG("删除源文件失败\n"); 164 | return result; 165 | } 166 | // 4. 临时文件重命名 167 | FileHelper helper(_tempfile); 168 | ret = helper.rename(_datafile); 169 | if (ret == false) 170 | ELOG("重命名临时文件失败\n"); 171 | 172 | return result; 173 | } 174 | 175 | private: 176 | std::string _qname; 177 | std::string _datafile; 178 | std::string _tempfile; 179 | }; 180 | 181 | class QueueMessage { 182 | private: 183 | bool gcCheck() { 184 | // 当数据达到两千条,并且有效数据低于50%的时候需要进行垃圾回收 185 | if (_total_count > 2000 && _valid_count * 10 / _total_count < 5) 186 | return true; 187 | else 188 | return false; 189 | } 190 | 191 | void gc() { 192 | if (this->gcCheck() == false) 193 | return; 194 | // 现在开始进行垃圾回收 195 | std::list msgs = _mapper.gc(); 196 | 197 | for (auto& msg : msgs) { 198 | auto it = _durable_msgs.find(msg->payload().properties().id()); 199 | if (it == _durable_msgs.end()) { 200 | ELOG("有一条消息没有被持久化管理\n"); 201 | msgs.push_back(msg); 202 | _durable_msgs[msg->payload().properties().id()] = msg; 203 | continue; 204 | } 205 | // 需要重新设置消息的偏移量和长度 206 | it->second->set_offset(msg->offset()); 207 | it->second->set_length(msg->length()); 208 | } 209 | _valid_count = msgs.size(); 210 | _total_count = msgs.size(); 211 | } 212 | 213 | public: 214 | using ptr = std::shared_ptr; 215 | 216 | QueueMessage(const std::string& basedir, const std::string& qname) 217 | : _qname(qname), 218 | _mapper(basedir, qname), 219 | _valid_count(0), 220 | _total_count(0) 221 | {} 222 | 223 | void recovery() { 224 | // 恢复消息 225 | std::unique_lock lock(_mutex); 226 | _msgs = _mapper.gc(); 227 | for (auto& msg : _msgs) { 228 | _durable_msgs.insert(std::make_pair(msg->payload().properties().id(), msg)); 229 | DLOG("恢复消息:%s\n", msg->payload().body().c_str()); 230 | } 231 | _valid_count = _msgs.size(); 232 | _total_count = _msgs.size(); 233 | } 234 | 235 | void garbageRecive() { 236 | this->recovery(); 237 | } 238 | 239 | bool insert(const BasicProperties* bp, const std::string& body, bool queue_durable) { 240 | // 1.先构造对应的消息 241 | MessagePtr msg = std::make_shared(); 242 | if (bp == nullptr) { 243 | DeliveryMode mode = queue_durable ? DeliveryMode::DURABLE : DeliveryMode::UNDURABLE; 244 | msg->mutable_payload()->mutable_properties()->set_id(UUIDHelper::uuid()); 245 | msg->mutable_payload()->mutable_properties()->set_delivery_mode(mode); 246 | msg->mutable_payload()->mutable_properties()->set_routing_key(std::string()); 247 | } else { 248 | DeliveryMode mode = queue_durable ? bp->delivery_mode() : DeliveryMode::UNDURABLE; 249 | msg->mutable_payload()->mutable_properties()->set_id(bp->id()); 250 | msg->mutable_payload()->mutable_properties()->set_delivery_mode(mode); 251 | msg->mutable_payload()->mutable_properties()->set_routing_key(bp->routing_key()); 252 | } 253 | msg->mutable_payload()->set_body(body); 254 | std::unique_lock lock(_mutex); 255 | // 2.判断消息是否需要持久化 256 | if (msg->payload().properties().delivery_mode() == DeliveryMode::DURABLE) { 257 | // 将消息进行持久化处理 258 | msg->mutable_payload()->set_vaild("1"); 259 | bool ret = _mapper.insert(msg); 260 | if (ret == false) { 261 | DLOG("持久化 %s 数据失败\n", body.c_str()); 262 | return false; 263 | } 264 | // 持久化数据加一 265 | _valid_count++; 266 | _total_count++; 267 | _durable_msgs[msg->payload().properties().id()] = msg; 268 | } 269 | // DLOG("当前插入消息内容: %s\n", msg->payload().body().c_str()); 270 | // 3.将消息加入到待推送链表中 271 | _msgs.push_back(msg); 272 | 273 | return true; 274 | } 275 | 276 | MessagePtr front() { 277 | // 拿出队首消息,然后发送出去 278 | std::unique_lock lock(_mutex); 279 | if (_msgs.size() == 0) 280 | return MessagePtr(); 281 | 282 | MessagePtr msg = _msgs.front(); 283 | _msgs.pop_front(); 284 | // 现在将拿出的队首消息加入到待确认消息 285 | _waitack_msgs[msg->payload().properties().id()] = msg; 286 | return msg; 287 | } 288 | 289 | bool remove(const std::string& msg_id) { 290 | // 删除数据是从待确认消息中进行删除 291 | std::unique_lock lock(_mutex); 292 | // 1.先查找该数据是否存在 293 | auto it = _waitack_msgs.find(msg_id); 294 | if (it == _waitack_msgs.end()) { 295 | ILOG("没有找到需要删除的消息 %s\n", msg_id.c_str()); 296 | return true; 297 | } 298 | // 2.判断拿到的消息是否存在持久化性质 299 | if (it->second->payload().properties().delivery_mode() == DeliveryMode::DURABLE) { 300 | // 还要将持久化的数据给删去 301 | _mapper.remove(it->second); 302 | _durable_msgs.erase(it->second->payload().properties().id()); 303 | // 持久化文件中的有效数据减一 304 | _valid_count--; 305 | this->gc(); 306 | } 307 | // 3.同时删除内存中的数据 308 | _waitack_msgs.erase(it->second->payload().properties().id()); 309 | return true; 310 | } 311 | 312 | size_t getable_count() { 313 | // 可获取到的数据 314 | std::unique_lock lock(_mutex); 315 | return _msgs.size(); 316 | } 317 | 318 | size_t total_count() { 319 | std::unique_lock lock(_mutex); 320 | return _total_count; 321 | } 322 | 323 | size_t waitack_count() { 324 | std::unique_lock lock(_mutex); 325 | return _waitack_msgs.size(); 326 | } 327 | 328 | size_t durable_count() { 329 | std::unique_lock lock(_mutex); 330 | return _durable_msgs.size(); 331 | } 332 | 333 | void clear() { 334 | std::unique_lock lock(_mutex); 335 | _mapper.removeMsgFile(); 336 | _msgs.clear(); 337 | _durable_msgs.clear(); 338 | _waitack_msgs.clear(); 339 | _valid_count = 0; 340 | _total_count = 0; 341 | } 342 | private: 343 | std::mutex _mutex; 344 | std::string _qname; // 队列名称 345 | MessageMapper _mapper; // 持久化操作句柄 346 | size_t _valid_count; // 有效消息数量 347 | size_t _total_count; // 总消息数量 348 | std::list _msgs; // 待推送消息链表 349 | std::unordered_map _durable_msgs; // 待持久消息hash 350 | std::unordered_map _waitack_msgs; // 待确认消息hash 351 | }; 352 | 353 | class MessageManager { 354 | public: 355 | using ptr = std::shared_ptr; 356 | 357 | MessageManager(const std::string& basedir) 358 | : _basedir(basedir) 359 | {} 360 | 361 | // 初始化队列消息 362 | void initQueueMessage(const std::string& qname) { 363 | QueueMessage::ptr msgp; 364 | { 365 | std::unique_lock lock(_mutex); 366 | // 查找当前hashmap中是否已经存在 367 | auto it = _queue_msgs.find(qname); 368 | if (it != _queue_msgs.end()) { 369 | // ILOG("当前队列消息已存在: %s\n", qname.c_str()); 370 | return; 371 | } 372 | msgp = std::make_shared(_basedir, qname); 373 | _queue_msgs[qname] = msgp; 374 | } 375 | // 恢复内存中的数据 376 | msgp->recovery(); 377 | } 378 | 379 | void destoryQueueMessahe(const std::string& qname) { 380 | QueueMessage::ptr msgp; 381 | { 382 | std::unique_lock lock(_mutex); 383 | auto it = _queue_msgs.find(qname); 384 | if (it == _queue_msgs.end()) { 385 | ILOG("当前需要删除的队列不存在: %s\n", qname.c_str()); 386 | return; 387 | } 388 | msgp = it->second; 389 | _queue_msgs.erase(qname); 390 | } 391 | msgp->clear(); 392 | } 393 | 394 | bool insert(const std::string& qname, const BasicProperties* bp, const std::string& body, bool queue_durable) { 395 | QueueMessage::ptr msgp; 396 | { 397 | std::unique_lock lock(_mutex); 398 | auto it = _queue_msgs.find(qname); 399 | if (it == _queue_msgs.end()) { 400 | ILOG("当前需要插入数据的队列不存在: %s\n", qname.c_str()); 401 | return false; 402 | } 403 | msgp = it->second; 404 | } 405 | return msgp->insert(bp, body, queue_durable); 406 | } 407 | 408 | // 对当前系统中存在的所有队列进行垃圾回收 409 | void gc() { 410 | std::unique_lock lock(_mutex); 411 | for (auto& it : _queue_msgs) { 412 | QueueMessage::ptr msgp = it.second; 413 | msgp->garbageRecive(); 414 | } 415 | } 416 | 417 | void ack(const std::string& qname, const std::string& msg_id) { 418 | // 确认消息,就是将消息在队列中删除 419 | QueueMessage::ptr msgp; 420 | { 421 | std::unique_lock lock(_mutex); 422 | auto it = _queue_msgs.find(qname); 423 | if (it == _queue_msgs.end()) { 424 | ILOG("当前需要删除消息的队列不存在: %s\n", qname.c_str()); 425 | return; 426 | } 427 | msgp = it->second; 428 | } 429 | msgp->remove(msg_id); 430 | } 431 | 432 | MessagePtr front(const std::string& qname) { 433 | QueueMessage::ptr msgp; 434 | { 435 | std::unique_lock lock(_mutex); 436 | auto it = _queue_msgs.find(qname); 437 | if (it == _queue_msgs.end()) { 438 | ILOG("当前队列不存在: %s\n", qname.c_str()); 439 | return MessagePtr(); 440 | } 441 | msgp = it->second; 442 | } 443 | return msgp->front(); 444 | } 445 | 446 | size_t getable_count(const std::string& qname) { 447 | QueueMessage::ptr msgp; 448 | { 449 | std::unique_lock lock(_mutex); 450 | auto it = _queue_msgs.find(qname); 451 | if (it == _queue_msgs.end()) { 452 | ILOG("当前队列不存在: %s\n", qname.c_str()); 453 | return 0; 454 | } 455 | msgp = it->second; 456 | } 457 | return msgp->getable_count(); 458 | } 459 | 460 | size_t total_count(const std::string& qname) { 461 | QueueMessage::ptr msgp; 462 | { 463 | std::unique_lock lock(_mutex); 464 | auto it = _queue_msgs.find(qname); 465 | if (it == _queue_msgs.end()) { 466 | ILOG("当前队列不存在: %s\n", qname.c_str()); 467 | return 0; 468 | } 469 | msgp = it->second; 470 | } 471 | return msgp->total_count(); 472 | } 473 | 474 | size_t waitack_count(const std::string& qname) { 475 | QueueMessage::ptr msgp; 476 | { 477 | std::unique_lock lock(_mutex); 478 | auto it = _queue_msgs.find(qname); 479 | if (it == _queue_msgs.end()) { 480 | ILOG("当前队列不存在: %s\n", qname.c_str()); 481 | return 0; 482 | } 483 | msgp = it->second; 484 | } 485 | return msgp->waitack_count(); 486 | } 487 | 488 | size_t durable_count(const std::string& qname) { 489 | QueueMessage::ptr msgp; 490 | { 491 | std::unique_lock lock(_mutex); 492 | auto it = _queue_msgs.find(qname); 493 | if (it == _queue_msgs.end()) { 494 | ILOG("当前队列不存在: %s\n", qname.c_str()); 495 | return 0; 496 | } 497 | msgp = it->second; 498 | } 499 | return msgp->durable_count(); 500 | } 501 | 502 | void clear() { 503 | std::unique_lock lock(_mutex); 504 | for (auto& it : _queue_msgs) 505 | it.second->clear(); 506 | } 507 | 508 | private: 509 | std::mutex _mutex; 510 | std::string _basedir; 511 | std::unordered_map _queue_msgs; 512 | }; 513 | 514 | } 515 | 516 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/queue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_QUEUE_H__ 2 | #define __M_QUEUE_H__ 3 | 4 | #include "../MqCommon/logger.hpp" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/msg.pb.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace mq { 16 | struct MsgQueue { 17 | std::string name; // 消息队列的名称 18 | bool durable; // 持久化标志 19 | bool exclusive; // 独占标志 20 | bool auto_delete; // 自动删除标志 21 | google::protobuf::Map args; // 其他参数,类型使用google中的map,与protobuf生成的文件相对应 22 | 23 | using ptr = std::shared_ptr; 24 | 25 | MsgQueue() {} 26 | 27 | MsgQueue(const std::string& msg_name, bool msg_durable, 28 | bool msg_exclusive, bool msg_auto_delete, 29 | const google::protobuf::Map& msg_args) 30 | : name(msg_name), 31 | durable(msg_durable), 32 | exclusive(msg_durable), 33 | auto_delete(msg_auto_delete), 34 | args(msg_args) 35 | {} 36 | 37 | // 设置args中的参数,类型为:"key=value&key=value....",相当于将数据反序列化 38 | void setArgs(const std::string& args_str) { 39 | if (args_str.empty()) 40 | return; 41 | std::vector kvs; 42 | StrHelper::split(args_str, "&", kvs); 43 | for (auto& kv : kvs) { 44 | // 现在将key,value放入到map中 45 | size_t pos = kv.find('='); 46 | std::string key = kv.substr(0, pos); 47 | std::string value = kv.substr(pos + 1); 48 | args[key] = value; 49 | } 50 | } 51 | 52 | // 将数据序列化 53 | std::string getArgs() { 54 | std::string result; 55 | for (auto& it : args) { 56 | std::string kv = it.first + "=" + it.second + "&"; 57 | result += kv; 58 | } 59 | return result; 60 | } 61 | }; 62 | 63 | class MsgQueueMapper { 64 | private: 65 | // 对应的持久化sqk语句 66 | #define SQL_DELETE_MQM "drop table if exists queue_table;" 67 | #define SQL_INSERT_MQM "insert into queue_table values ('%s', %d, %d, %d, '%s');" 68 | #define SQL_REMOVE_MQM "delete from queue_table where name=" 69 | #define SQL_CREATE_MQM "create table if not exists queue_table ( \ 70 | name varchar(32) primary key, \ 71 | durable int, \ 72 | exclusive int, \ 73 | auto_delete int, \ 74 | args varchar(128) \ 75 | );" 76 | #define SQL_SELECT_MQM "select name, durable, exclusive, auto_delete, args from queue_table;" 77 | 78 | static int selectCallback(void* args, int numcol, char** row, char** fields) { 79 | MsgQueueMap* queue_map = static_cast(args); 80 | MsgQueue::ptr queue = std::make_shared(); 81 | queue->name = row[0]; 82 | queue->durable = (bool)std::stoi(row[1]); 83 | queue->exclusive = (bool)std::stoi(row[2]); 84 | queue->auto_delete = (bool)std::stoi(row[3]); 85 | if (row[4]) queue->setArgs(row[4]); 86 | queue_map->insert(std::make_pair(queue->name, queue)); 87 | 88 | return 0; 89 | } 90 | public: 91 | using MsgQueueMap = std::unordered_map; 92 | 93 | MsgQueueMapper(const std::string& dbname) 94 | : _sql_helper(dbname) 95 | { 96 | // 先获取dbfile上级文件路径 97 | std::string parent_path = FileHelper::parentDirectory(dbname); 98 | // 创建父级目录 99 | FileHelper::createDirectory(parent_path); 100 | assert(_sql_helper.open()); 101 | createTable(); 102 | } 103 | 104 | void createTable() { 105 | int ret = _sql_helper.exec(SQL_CREATE_MQM, nullptr, nullptr); 106 | if (ret == false) { 107 | ELOG("表格创建失败\n"); 108 | abort(); 109 | } 110 | } 111 | 112 | void removeTable() { 113 | int ret = _sql_helper.exec(SQL_DELETE_MQM, nullptr, nullptr); 114 | if (ret == false) { 115 | ELOG("表格删除失败\n"); 116 | abort(); 117 | } 118 | } 119 | 120 | bool insert(MsgQueue::ptr& msgqueue) { 121 | char buff[256]; 122 | int n = snprintf(buff, sizeof(buff) - 1, SQL_INSERT_MQM, 123 | (char*)msgqueue->name.c_str(), 124 | msgqueue->durable, 125 | msgqueue->exclusive, 126 | msgqueue->auto_delete, 127 | (char*)msgqueue->getArgs().c_str()); 128 | 129 | buff[n] = 0; 130 | std::string sql_insert(buff); 131 | sql_insert += ";"; 132 | return _sql_helper.exec(sql_insert, nullptr, nullptr); 133 | } 134 | 135 | void remove(const std::string& name) { 136 | std::stringstream sql_remove; 137 | sql_remove << SQL_REMOVE_MQM; 138 | sql_remove << "'" << name << "'"; 139 | int ret = _sql_helper.exec(sql_remove.str(), nullptr, nullptr); 140 | if (ret == false) 141 | ELOG("删除消息队列数据失败\n"); 142 | } 143 | 144 | // 恢复所有持久化的数据 145 | MsgQueueMap recovery() { 146 | MsgQueueMap result; 147 | int ret = _sql_helper.exec(SQL_SELECT_MQM, selectCallback, (void*)(&result)); 148 | return result; 149 | } 150 | private: 151 | // sqlite数据管理句柄 152 | SqliteHelper _sql_helper; 153 | }; 154 | 155 | class MsgQueueManager { 156 | public: 157 | using ptr = std::shared_ptr; 158 | 159 | MsgQueueManager(const std::string& dbfile) 160 | : _mapper(dbfile) 161 | { 162 | _msg_queues = _mapper.recovery(); 163 | } 164 | 165 | size_t size() { 166 | std::unique_lock lock(_mutex); 167 | return _msg_queues.size(); 168 | } 169 | 170 | bool exists(const std::string& name) { 171 | auto it = _msg_queues.find(name); 172 | if (it == _msg_queues.end()) 173 | return false; 174 | else 175 | return true; 176 | } 177 | 178 | void clear() { 179 | _mapper.removeTable(); 180 | _msg_queues.clear(); 181 | } 182 | 183 | bool declareQueue(const std::string& msg_name, bool msg_durable, 184 | bool msg_exclusive, bool msg_auto_delete, 185 | const google::protobuf::Map& msg_args) { 186 | std::unique_lock lock(_mutex); 187 | auto it = _msg_queues.find(msg_name); 188 | // 若已经存在,则不用插入 189 | if (it != _msg_queues.end()) 190 | return true; 191 | MsgQueue::ptr mqp = std::make_shared(); 192 | mqp->name = msg_name; 193 | mqp->durable = msg_durable; 194 | mqp->auto_delete = msg_auto_delete; 195 | mqp->args = msg_args; 196 | mqp->exclusive = msg_exclusive; 197 | if (msg_durable == true) { 198 | int ret = _mapper.insert(mqp); 199 | if (ret == false) 200 | return false; 201 | } 202 | _msg_queues[mqp->name] = mqp; 203 | return true; 204 | } 205 | 206 | void deleteQueue(const std::string& name) { 207 | std::unique_lock lock(_mutex); 208 | auto it = _msg_queues.find(name); 209 | // 若当前队列中已经没有了该队列 210 | if (it == _msg_queues.end()) 211 | return; 212 | if (it->second->durable) 213 | _mapper.remove(name); 214 | _msg_queues.erase(it->first); 215 | } 216 | 217 | MsgQueue::ptr selectQueue(const std::string& name) { 218 | std::unique_lock lock(_mutex); 219 | auto it = _msg_queues.find(name); 220 | // 若当前队列中已经没有了该队列 221 | if (it == _msg_queues.end()) 222 | return MsgQueue::ptr(); 223 | return _msg_queues[name]; 224 | } 225 | 226 | MsgQueueMapper::MsgQueueMap allQueue() { 227 | // 直接返回队列的映射 228 | return _msg_queues; 229 | } 230 | 231 | private: 232 | 233 | std::mutex _mutex; 234 | MsgQueueMapper _mapper; 235 | MsgQueueMapper::MsgQueueMap _msg_queues; 236 | }; 237 | } 238 | 239 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/route.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_ROUTE_H__ 2 | #define __M_ROUTE_H__ 3 | 4 | #include "../MqCommon/msg.pb.h" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/logger.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace mq { 12 | class Router { 13 | public: 14 | static bool isLegalRoutingKey(const std::string& routing_key) { 15 | // 判断当前的routingkey是否合法 16 | for (auto& ch : routing_key) { 17 | if ((ch >= 'a' && ch <= 'z') || 18 | (ch >= 'A' && ch <= 'Z') || 19 | (ch >= '0' && ch <= '9') || 20 | (ch == '_' || ch == '.') ) 21 | continue; 22 | return false; 23 | } 24 | return true; 25 | } 26 | 27 | static bool isLegalBindingKey(const std::string& binding_key) { 28 | // 1. 先判断是否存在非法字符 29 | for (auto& ch : binding_key) { 30 | if ((ch >= 'a' && ch <= 'z') || 31 | (ch >= 'A' && ch <= 'Z') || 32 | (ch >= '0' && ch <= '9') || 33 | (ch == '_' || ch == '.') || 34 | (ch == '*' || ch == '#')) 35 | continue; 36 | return false; 37 | } 38 | 39 | // 2. 判断* #是否和其他字符相连接 40 | std::vector sub_words; 41 | StrHelper::split(binding_key, ".", sub_words); 42 | for (auto& word : sub_words) { 43 | if (word.size() > 1 && (word.find('#') != std::string::npos || word.find('*') != std::string::npos)) 44 | return false; 45 | } 46 | 47 | // 3. 判断* #是否连接一起 48 | for (int i = 1; i < sub_words.size(); i++) { 49 | if (sub_words[i] == "#" && sub_words[i - 1] == "*") 50 | return false; 51 | if (sub_words[i] == "#" && sub_words[i - 1] == "#") 52 | return false; 53 | if (sub_words[i] == "*" && sub_words[i - 1] == "#") 54 | return false; 55 | } 56 | return true; 57 | } 58 | 59 | static bool route(ExchangeType type, const std::string& routing_key, const std::string& binding_key) { 60 | if (type == ExchangeType::DIRECT) 61 | return routing_key == binding_key; 62 | else if (type == ExchangeType::FANOUT) 63 | return true; 64 | // 使用动态规划来判断当前是否匹配 65 | std::vector bkeys, rkeys; 66 | int n_bkey = StrHelper::split(binding_key, ".", bkeys); 67 | int n_rkey = StrHelper::split(routing_key, ".", rkeys); 68 | std::vector> dp(n_bkey + 1, std::vector(n_rkey + 1, false)); 69 | dp[0][0] = true; 70 | if (n_bkey > 0 && bkeys[0] == "#") 71 | dp[1][0] = true; 72 | for (int i = 1; i <= n_bkey; i++) 73 | for (int j = 1; j <= n_rkey; j++) { 74 | if (bkeys[i - 1] == "*" || rkeys[j - 1] == bkeys[i - 1]) 75 | dp[i][j] = dp[i - 1][j - 1]; 76 | else if (bkeys[i - 1] == "#") 77 | dp[i][j] = dp[i - 1][j - 1] | dp[i][j - 1] | dp[i - 1][j]; 78 | } 79 | return dp[n_bkey][n_rkey]; 80 | } 81 | 82 | }; 83 | 84 | } 85 | 86 | 87 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqServer/server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/MessageQueue/MqServer/server -------------------------------------------------------------------------------- /MessageQueue/MqServer/server.cc: -------------------------------------------------------------------------------- 1 | #include "broker.hpp" 2 | 3 | int main() { 4 | mq::BrokerServer server(8085, "./data/"); 5 | server.start(); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /MessageQueue/MqServer/users.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __M_USERS_H__ 2 | #define __M_USERS_H__ 3 | 4 | #include "../MqCommon/user.pb.h" 5 | #include "../MqCommon/helper.hpp" 6 | #include "../MqCommon/logger.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace mq { 15 | // using UserLoginPtr = std::shared_ptr; 16 | // using userRegisterPtr = std::shared_ptr; 17 | 18 | class User { 19 | public: 20 | using ptr = std::shared_ptr; 21 | std::string username; 22 | std::string password; 23 | int user_type; 24 | 25 | User() {} 26 | 27 | User(const std::string& uname, const std::string& psword, int type) 28 | : username(uname), 29 | password(psword), 30 | user_type(type) 31 | {} 32 | }; 33 | 34 | // using UserMap = std::unordered_map; 35 | using UserMap = std::unordered_map>; 36 | 37 | class UserMapper { 38 | private: 39 | // 对应的持久化sqk语句 40 | #define SQL_DELETE_USR "drop table if exists user_table;" 41 | #define SQL_INSERT_USR "insert into user_table values ('%s', '%s', %d);" 42 | #define SQL_REMOVE_USR "delete from user_table where username=" 43 | #define SQL_CREATE_USR "create table if not exists user_table ( \ 44 | username varchar(32) primary key, \ 45 | password varchar(128), \ 46 | usertype int \ 47 | );" 48 | #define SQL_SELECT_USR "select username, password, usertype from user_table;" 49 | 50 | static int selectCallback(void* args, int numcol, char** row, char** fields) { 51 | UserMap* users = static_cast(args); 52 | User::ptr up = std::make_shared(row[0], row[1], std::stoi(row[2])); 53 | // 在user中插入元素 54 | // users->insert(std::make_pair(up->username, up->password)); 55 | (*users)[up->username] = std::make_pair(up->password, up->user_type); 56 | return 0; 57 | } 58 | 59 | public: 60 | UserMapper(const std::string& dbname) 61 | : _sql_helper(dbname) 62 | { 63 | // 获取父级路径 64 | std::string parentPath = FileHelper::parentDirectory(dbname); 65 | // 创建父级路径 66 | FileHelper::createDirectory(parentPath); 67 | assert(_sql_helper.open()); 68 | // 创建user数据库表 69 | this->createTable(); 70 | } 71 | 72 | void createTable() { 73 | int ret = _sql_helper.exec(SQL_CREATE_USR, nullptr, nullptr); 74 | if (ret == false) { 75 | ELOG("表格创建失败\n"); 76 | abort(); 77 | } 78 | } 79 | 80 | void removeTable() { 81 | int ret = _sql_helper.exec(SQL_DELETE_USR, nullptr, nullptr); 82 | if (ret == false) { 83 | ELOG("表格删除失败\n"); 84 | abort(); 85 | } 86 | } 87 | 88 | // 主要提供两个接口 89 | // 一个用户注销,一个用户注册 90 | bool Register(const User::ptr& user) { 91 | // 在底层数据库中查找是否存在该用 92 | 93 | char buff[256]; 94 | int n = snprintf(buff, sizeof(buff) - 1, SQL_INSERT_USR, 95 | (char*)user->username.c_str(), 96 | (char*)user->password.c_str(), 97 | user->user_type 98 | ); 99 | buff[n] = 0; 100 | std::string sql_insert(buff); 101 | return _sql_helper.exec(sql_insert, nullptr, nullptr); 102 | } 103 | 104 | // 用户注销 105 | void Logout(const std::string& username) { 106 | std::stringstream sql_remove; 107 | sql_remove << SQL_REMOVE_USR; 108 | sql_remove << "'" << username << "';"; 109 | int ret = _sql_helper.exec(sql_remove.str(), nullptr, nullptr); 110 | if (ret == false) 111 | ELOG("注销用户失败\n"); 112 | } 113 | 114 | UserMap recovery() { 115 | UserMap users; 116 | int ret = _sql_helper.exec(SQL_SELECT_USR, selectCallback, (void*)(&users)); 117 | return users; 118 | } 119 | private: 120 | SqliteHelper _sql_helper; 121 | }; 122 | 123 | class UserManager { 124 | public: 125 | using ptr = std::shared_ptr; 126 | 127 | UserManager(const std::string& dbfile) 128 | : _mapper(dbfile) 129 | { 130 | _users = _mapper.recovery(); 131 | // 查看users中是否存在admin,不存在插入管理员用户 132 | auto it = _users.find("admin"); 133 | if (it == _users.end()) { 134 | bool ret = _mapper.Register(std::make_shared("admin", "123456", 0)); 135 | if (ret) 136 | _users["admin"] = std::make_pair("123456", 0); 137 | else 138 | ELOG("管理员用户加载失败\n"); 139 | } 140 | } 141 | 142 | // 用户登陆,用户注销,用户注册 143 | std::pair login(const std::string& username, const std::string& password) { 144 | // User user(username, password); 145 | auto it = _users.find(username); 146 | if (it == _users.end() || it->second.first != password) 147 | return std::make_pair(false, -1); 148 | else 149 | return std::make_pair(true, it->second.second); 150 | } 151 | 152 | // 注销 153 | void logout(const std::string& username) { 154 | _mapper.Logout(username); 155 | _users.erase(username); 156 | } 157 | 158 | // 注册 159 | bool signIn(const std::string& username, const std::string& password, UserType user_type) { 160 | auto it = _users.find(username); 161 | // 用户已经存在 162 | if (it != _users.end()) 163 | return false; 164 | // 1表示接收者 2表示推送者 165 | int type = user_type == mq::RECIVER ? 1 : 2; 166 | 167 | 168 | bool ret = _mapper.Register(std::make_shared(username, password, type)); 169 | if (ret) 170 | _users[username] = std::make_pair(password, type); 171 | return ret; 172 | } 173 | 174 | UserMap allUsers() { 175 | return _users; 176 | } 177 | 178 | std::string getAllUsers() { 179 | // 使用username~~~password%%%usertype~~%%username~~~password%%%usertype 180 | _users = _mapper.recovery(); 181 | std::string user_psword_sep("~~~"); 182 | std::string psword_type_sep("%%%"); 183 | std::string users_sep("~~%%"); 184 | std::string allUsers; 185 | for (auto& user : _users) { 186 | std::string u; 187 | u += user.first + user_psword_sep; 188 | u += user.second.first + psword_type_sep; 189 | u += std::to_string(user.second.second); 190 | allUsers += u + users_sep; 191 | } 192 | ILOG("all users: %s\n", allUsers.c_str()); 193 | return allUsers; 194 | } 195 | private: 196 | UserMapper _mapper; 197 | UserMap _users; 198 | 199 | // 在用户模块,0表示管理员用户,1表示消息接收用户,2表示消息发布用户 200 | }; 201 | 202 | } 203 | 204 | #endif -------------------------------------------------------------------------------- /MessageQueue/MqThird/include/codec.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2011, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | // 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "codec.h" 10 | 11 | #include "muduo/base/Logging.h" 12 | #include "muduo/net/Endian.h" 13 | #include "google-inl.h" 14 | 15 | #include 16 | 17 | #include // adler32 18 | 19 | using namespace muduo; 20 | using namespace muduo::net; 21 | 22 | void ProtobufCodec::fillEmptyBuffer(Buffer* buf, const google::protobuf::Message& message) 23 | { 24 | // buf->retrieveAll(); 25 | assert(buf->readableBytes() == 0); 26 | 27 | const std::string& typeName = message.GetTypeName(); 28 | int32_t nameLen = static_cast(typeName.size()+1); 29 | buf->appendInt32(nameLen); 30 | buf->append(typeName.c_str(), nameLen); 31 | 32 | // code copied from MessageLite::SerializeToArray() and MessageLite::SerializePartialToArray(). 33 | GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); 34 | 35 | /** 36 | * 'ByteSize()' of message is deprecated in Protocol Buffers v3.4.0 firstly. 37 | * But, till to v3.11.0, it just getting start to be marked by '__attribute__((deprecated()))'. 38 | * So, here, v3.9.2 is selected as maximum version using 'ByteSize()' to avoid 39 | * potential effect for previous muduo code/projects as far as possible. 40 | * Note: All information above just INFER from 41 | * 1) https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0 42 | * 2) MACRO in file 'include/google/protobuf/port_def.inc'. 43 | * eg. '#define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))'. 44 | * In addition, usage of 'ToIntSize()' comes from Impl of ByteSize() in new version's Protocol Buffers. 45 | */ 46 | 47 | #if GOOGLE_PROTOBUF_VERSION > 3009002 48 | int byte_size = google::protobuf::internal::ToIntSize(message.ByteSizeLong()); 49 | #else 50 | int byte_size = message.ByteSize(); 51 | #endif 52 | buf->ensureWritableBytes(byte_size); 53 | 54 | uint8_t* start = reinterpret_cast(buf->beginWrite()); 55 | uint8_t* end = message.SerializeWithCachedSizesToArray(start); 56 | if (end - start != byte_size) 57 | { 58 | #if GOOGLE_PROTOBUF_VERSION > 3009002 59 | ByteSizeConsistencyError(byte_size, google::protobuf::internal::ToIntSize(message.ByteSizeLong()), static_cast(end - start)); 60 | #else 61 | ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); 62 | #endif 63 | } 64 | buf->hasWritten(byte_size); 65 | 66 | int32_t checkSum = static_cast( 67 | ::adler32(1, 68 | reinterpret_cast(buf->peek()), 69 | static_cast(buf->readableBytes()))); 70 | buf->appendInt32(checkSum); 71 | assert(buf->readableBytes() == sizeof nameLen + nameLen + byte_size + sizeof checkSum); 72 | int32_t len = sockets::hostToNetwork32(static_cast(buf->readableBytes())); 73 | buf->prepend(&len, sizeof len); 74 | } 75 | 76 | // 77 | // no more google code after this 78 | // 79 | 80 | // 81 | // FIXME: merge with RpcCodec 82 | // 83 | 84 | namespace 85 | { 86 | const string kNoErrorStr = "NoError"; 87 | const string kInvalidLengthStr = "InvalidLength"; 88 | const string kCheckSumErrorStr = "CheckSumError"; 89 | const string kInvalidNameLenStr = "InvalidNameLen"; 90 | const string kUnknownMessageTypeStr = "UnknownMessageType"; 91 | const string kParseErrorStr = "ParseError"; 92 | const string kUnknownErrorStr = "UnknownError"; 93 | } 94 | 95 | const string& ProtobufCodec::errorCodeToString(ErrorCode errorCode) 96 | { 97 | switch (errorCode) 98 | { 99 | case kNoError: 100 | return kNoErrorStr; 101 | case kInvalidLength: 102 | return kInvalidLengthStr; 103 | case kCheckSumError: 104 | return kCheckSumErrorStr; 105 | case kInvalidNameLen: 106 | return kInvalidNameLenStr; 107 | case kUnknownMessageType: 108 | return kUnknownMessageTypeStr; 109 | case kParseError: 110 | return kParseErrorStr; 111 | default: 112 | return kUnknownErrorStr; 113 | } 114 | } 115 | 116 | void ProtobufCodec::defaultErrorCallback(const muduo::net::TcpConnectionPtr& conn, 117 | muduo::net::Buffer* buf, 118 | muduo::Timestamp, 119 | ErrorCode errorCode) 120 | { 121 | LOG_ERROR << "ProtobufCodec::defaultErrorCallback - " << errorCodeToString(errorCode); 122 | if (conn && conn->connected()) 123 | { 124 | conn->shutdown(); 125 | } 126 | } 127 | 128 | int32_t asInt32(const char* buf) 129 | { 130 | int32_t be32 = 0; 131 | ::memcpy(&be32, buf, sizeof(be32)); 132 | return sockets::networkToHost32(be32); 133 | } 134 | 135 | void ProtobufCodec::onMessage(const TcpConnectionPtr& conn, 136 | Buffer* buf, 137 | Timestamp receiveTime) 138 | { 139 | while (buf->readableBytes() >= kMinMessageLen + kHeaderLen) 140 | { 141 | const int32_t len = buf->peekInt32(); 142 | if (len > kMaxMessageLen || len < kMinMessageLen) 143 | { 144 | errorCallback_(conn, buf, receiveTime, kInvalidLength); 145 | break; 146 | } 147 | else if (buf->readableBytes() >= implicit_cast(len + kHeaderLen)) 148 | { 149 | ErrorCode errorCode = kNoError; 150 | MessagePtr message = parse(buf->peek()+kHeaderLen, len, &errorCode); 151 | if (errorCode == kNoError && message) 152 | { 153 | messageCallback_(conn, message, receiveTime); 154 | buf->retrieve(kHeaderLen+len); 155 | } 156 | else 157 | { 158 | errorCallback_(conn, buf, receiveTime, errorCode); 159 | break; 160 | } 161 | } 162 | else 163 | { 164 | break; 165 | } 166 | } 167 | } 168 | 169 | google::protobuf::Message* ProtobufCodec::createMessage(const std::string& typeName) 170 | { 171 | google::protobuf::Message* message = NULL; 172 | const google::protobuf::Descriptor* descriptor = 173 | google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(typeName); 174 | if (descriptor) 175 | { 176 | const google::protobuf::Message* prototype = 177 | google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); 178 | if (prototype) 179 | { 180 | message = prototype->New(); 181 | } 182 | } 183 | return message; 184 | } 185 | 186 | MessagePtr ProtobufCodec::parse(const char* buf, int len, ErrorCode* error) 187 | { 188 | MessagePtr message; 189 | 190 | // check sum 191 | int32_t expectedCheckSum = asInt32(buf + len - kHeaderLen); 192 | int32_t checkSum = static_cast( 193 | ::adler32(1, 194 | reinterpret_cast(buf), 195 | static_cast(len - kHeaderLen))); 196 | if (checkSum == expectedCheckSum) 197 | { 198 | // get message type name 199 | int32_t nameLen = asInt32(buf); 200 | if (nameLen >= 2 && nameLen <= len - 2*kHeaderLen) 201 | { 202 | std::string typeName(buf + kHeaderLen, buf + kHeaderLen + nameLen - 1); 203 | // create message object 204 | message.reset(createMessage(typeName)); 205 | if (message) 206 | { 207 | // parse from buffer 208 | const char* data = buf + kHeaderLen + nameLen; 209 | int32_t dataLen = len - nameLen - 2*kHeaderLen; 210 | if (message->ParseFromArray(data, dataLen)) 211 | { 212 | *error = kNoError; 213 | } 214 | else 215 | { 216 | *error = kParseError; 217 | } 218 | } 219 | else 220 | { 221 | *error = kUnknownMessageType; 222 | } 223 | } 224 | else 225 | { 226 | *error = kInvalidNameLen; 227 | } 228 | } 229 | else 230 | { 231 | *error = kCheckSumError; 232 | } 233 | 234 | return message; 235 | } 236 | -------------------------------------------------------------------------------- /MessageQueue/MqThird/include/codec.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | // 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #ifndef MUDUO_EXAMPLES_PROTOBUF_CODEC_CODEC_H 10 | #define MUDUO_EXAMPLES_PROTOBUF_CODEC_CODEC_H 11 | 12 | #include "muduo/net/Buffer.h" 13 | #include "muduo/net/TcpConnection.h" 14 | 15 | #include 16 | 17 | // struct ProtobufTransportFormat __attribute__ ((__packed__)) 18 | // { 19 | // int32_t len; 20 | // int32_t nameLen; 21 | // char typeName[nameLen]; 22 | // char protobufData[len-nameLen-8]; 23 | // int32_t checkSum; // adler32 of nameLen, typeName and protobufData 24 | // } 25 | 26 | typedef std::shared_ptr MessagePtr; 27 | 28 | // 29 | // FIXME: merge with RpcCodec 30 | // 31 | class ProtobufCodec : muduo::noncopyable 32 | { 33 | public: 34 | 35 | enum ErrorCode 36 | { 37 | kNoError = 0, 38 | kInvalidLength, 39 | kCheckSumError, 40 | kInvalidNameLen, 41 | kUnknownMessageType, 42 | kParseError, 43 | }; 44 | 45 | typedef std::function ProtobufMessageCallback; 48 | 49 | typedef std::function ErrorCallback; 53 | 54 | explicit ProtobufCodec(const ProtobufMessageCallback& messageCb) 55 | : messageCallback_(messageCb), 56 | errorCallback_(defaultErrorCallback) 57 | { 58 | } 59 | 60 | ProtobufCodec(const ProtobufMessageCallback& messageCb, const ErrorCallback& errorCb) 61 | : messageCallback_(messageCb), 62 | errorCallback_(errorCb) 63 | { 64 | } 65 | 66 | void onMessage(const muduo::net::TcpConnectionPtr& conn, 67 | muduo::net::Buffer* buf, 68 | muduo::Timestamp receiveTime); 69 | 70 | void send(const muduo::net::TcpConnectionPtr& conn, 71 | const google::protobuf::Message& message) 72 | { 73 | // FIXME: serialize to TcpConnection::outputBuffer() 74 | muduo::net::Buffer buf; 75 | fillEmptyBuffer(&buf, message); 76 | conn->send(&buf); 77 | } 78 | 79 | static const muduo::string& errorCodeToString(ErrorCode errorCode); 80 | static void fillEmptyBuffer(muduo::net::Buffer* buf, const google::protobuf::Message& message); 81 | static google::protobuf::Message* createMessage(const std::string& type_name); 82 | static MessagePtr parse(const char* buf, int len, ErrorCode* errorCode); 83 | 84 | private: 85 | static void defaultErrorCallback(const muduo::net::TcpConnectionPtr&, 86 | muduo::net::Buffer*, 87 | muduo::Timestamp, 88 | ErrorCode); 89 | 90 | ProtobufMessageCallback messageCallback_; 91 | ErrorCallback errorCallback_; 92 | 93 | const static int kHeaderLen = sizeof(int32_t); 94 | const static int kMinMessageLen = 2*kHeaderLen + 2; // nameLen + typeName + checkSum 95 | const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit 96 | }; 97 | 98 | #endif // MUDUO_EXAMPLES_PROTOBUF_CODEC_CODEC_H 99 | -------------------------------------------------------------------------------- /MessageQueue/MqThird/include/dispatcher.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | // 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #ifndef MUDUO_EXAMPLES_PROTOBUF_CODEC_DISPATCHER_H 10 | #define MUDUO_EXAMPLES_PROTOBUF_CODEC_DISPATCHER_H 11 | 12 | #include "muduo/base/noncopyable.h" 13 | #include "muduo/net/Callbacks.h" 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | typedef std::shared_ptr MessagePtr; 22 | 23 | class Callback : muduo::noncopyable 24 | { 25 | public: 26 | virtual ~Callback() = default; 27 | virtual void onMessage(const muduo::net::TcpConnectionPtr&, 28 | const MessagePtr& message, 29 | muduo::Timestamp) const = 0; 30 | }; 31 | 32 | template 33 | class CallbackT : public Callback 34 | { 35 | static_assert(std::is_base_of::value, 36 | "T must be derived from gpb::Message."); 37 | public: 38 | typedef std::function& message, 40 | muduo::Timestamp)> ProtobufMessageTCallback; 41 | 42 | CallbackT(const ProtobufMessageTCallback& callback) 43 | : callback_(callback) 44 | { 45 | } 46 | 47 | void onMessage(const muduo::net::TcpConnectionPtr& conn, 48 | const MessagePtr& message, 49 | muduo::Timestamp receiveTime) const override 50 | { 51 | std::shared_ptr concrete = muduo::down_pointer_cast(message); 52 | assert(concrete != NULL); 53 | callback_(conn, concrete, receiveTime); 54 | } 55 | 56 | private: 57 | ProtobufMessageTCallback callback_; 58 | }; 59 | 60 | class ProtobufDispatcher 61 | { 62 | public: 63 | typedef std::function ProtobufMessageCallback; 66 | 67 | explicit ProtobufDispatcher(const ProtobufMessageCallback& defaultCb) 68 | : defaultCallback_(defaultCb) 69 | { 70 | } 71 | 72 | void onProtobufMessage(const muduo::net::TcpConnectionPtr& conn, 73 | const MessagePtr& message, 74 | muduo::Timestamp receiveTime) const 75 | { 76 | CallbackMap::const_iterator it = callbacks_.find(message->GetDescriptor()); 77 | if (it != callbacks_.end()) 78 | { 79 | it->second->onMessage(conn, message, receiveTime); 80 | } 81 | else 82 | { 83 | defaultCallback_(conn, message, receiveTime); 84 | } 85 | } 86 | 87 | template 88 | void registerMessageCallback(const typename CallbackT::ProtobufMessageTCallback& callback) 89 | { 90 | std::shared_ptr > pd(new CallbackT(callback)); 91 | callbacks_[T::descriptor()] = pd; 92 | } 93 | 94 | private: 95 | typedef std::map > CallbackMap; 96 | 97 | CallbackMap callbacks_; 98 | ProtobufMessageCallback defaultCallback_; 99 | }; 100 | #endif // MUDUO_EXAMPLES_PROTOBUF_CODEC_DISPATCHER_H 101 | 102 | -------------------------------------------------------------------------------- /MessageQueue/MqThird/include/google-inl.h: -------------------------------------------------------------------------------- 1 | // ByteSizeConsistencyError and InitializationErrorMessage are 2 | // copied from google/protobuf/message_lite.cc 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // http://code.google.com/p/protobuf/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | // Authors: wink@google.com (Wink Saville), 35 | // kenton@google.com (Kenton Varda) 36 | // Based on original Protocol Buffers design by 37 | // Sanjay Ghemawat, Jeff Dean, and others. 38 | 39 | #include 40 | 41 | // When serializing, we first compute the byte size, then serialize the message. 42 | // If serialization produces a different number of bytes than expected, we 43 | // call this function, which crashes. The problem could be due to a bug in the 44 | // protobuf implementation but is more likely caused by concurrent modification 45 | // of the message. This function attempts to distinguish between the two and 46 | // provide a useful error message. 47 | inline 48 | void ByteSizeConsistencyError(int byte_size_before_serialization, 49 | int byte_size_after_serialization, 50 | int bytes_produced_by_serialization) 51 | { 52 | GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) 53 | << "Protocol message was modified concurrently during serialization."; 54 | GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) 55 | << "Byte size calculation and serialization were inconsistent. This " 56 | "may indicate a bug in protocol buffers or it may be caused by " 57 | "concurrent modification of the message."; 58 | GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; 59 | } 60 | 61 | inline 62 | std::string InitializationErrorMessage(const char* action, 63 | const google::protobuf::MessageLite& message) 64 | { 65 | // Note: We want to avoid depending on strutil in the lite library, otherwise 66 | // we'd use: 67 | // 68 | // return strings::Substitute( 69 | // "Can't $0 message of type \"$1\" because it is missing required " 70 | // "fields: $2", 71 | // action, message.GetTypeName(), 72 | // message.InitializationErrorString()); 73 | 74 | std::string result; 75 | result += "Can't "; 76 | result += action; 77 | result += " message of type \""; 78 | result += message.GetTypeName(); 79 | result += "\" because it is missing required fields: "; 80 | result += message.InitializationErrorString(); 81 | return result; 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于AMQP协议的消息订阅转发系统 2 | 3 | [TOC] 4 | 5 | ## 简介 6 | 7 | ​ 实现了一个基于AMQP(Advanced Message Queuing Protocol)协议的消息订阅与转发系统,主要实现的是将通过三种不同的订阅模式,将消息通过服务器端路由转发到对应的用户手中。 8 | 9 | > 三种订阅模式为: 10 | > 11 | > - 主题订阅:当订阅了某一类信息时,那么将会接收到这一类的信息,比如我订阅的是运动新闻,那么将会收到的来自篮球、足球、 排球等各类新闻,但是其他的娱乐新闻却收不到。 12 | > - 直连订阅:当订阅了某一种信息时,只能收到这种信息,比如我指定订阅了NBA的新闻,那么只会接收到来自NBA的新闻。 13 | > - 广播订阅:当订阅了某一个消息发布者之后,将会收到来自该发布者发布的所有信息。 14 | 15 | ​ 整个系统分为三端:服务器端、消息发送端、消息接收端。消息接收端和消息发送端都可以声明不同订阅模式的交换机以及消息队列,同时将交换机与消息队列通过特定的绑定关系绑定起来。 16 | 17 | ​ 当消息由消息发送端发送至服务器时,首先是发送至服务器内的交换机中,接着通过消息自带的路由标签和交换机与队列之间的绑定关系进行路由匹配,然后发送给对应的消息队列,最后通过消息队列发送到对应的消息接收端。 18 | 19 | ## 安装环境 20 | 21 | ​ 接下来便是进行环境配置。该代码是在Linux下开发的,调用了一些系统调用接口,所以只能在Linux环境下运行。一下环境是本人在ubuntu22.04版本下配置的环境。 22 | 23 | ### 基础环境搭建 24 | 25 | ​ 先更新软件包源 26 | 27 | ``` 28 | sudo apt update 29 | ``` 30 | 31 | ​ 安装wget 32 | 33 | ``` 34 | sudo apt-get install wget 35 | ``` 36 | 37 | ​ 安装编译器 38 | 39 | ``` 40 | sudo apt-get install gcc g++ 41 | ``` 42 | 43 | ​ 按章项目构建工具 44 | 45 | ``` 46 | sudo apt-get install make 47 | ``` 48 | 49 | ​ 安装git 50 | 51 | ``` 52 | sudo apt-get install git 53 | ``` 54 | 55 | ​ 安装cmake 56 | 57 | ``` 58 | sudo apt-get install cmake 59 | ``` 60 | 61 | ### 安装protobuf 62 | 63 | ​ 移除现有的protobuf(因为不同版本的protobuf可能存在编译不过的情况,本项目使用的是protobuf 3.14.0 版本) 64 | 65 | ``` 66 | sudo apt-get remove --purge protobuf-compiler libprotobuf-dev libprotobuf17 67 | ``` 68 | 69 | ​ 安装编译源码所需的工具以及依赖 70 | 71 | ``` 72 | sudo apt-get install -y build-essential autoconf automake libtool curl make g++ unzip 73 | ``` 74 | 75 | ​ 下载protobuf 3.14.0的源码包 76 | 77 | ``` 78 | curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protobuf-all-3.14.0.tar.gz 79 | ``` 80 | 81 | ​ 解压并进入目录 82 | 83 | ``` 84 | tar -xzvf protobuf-all-3.14.0.tar.gz 85 | cd protobuf-3.14.0 86 | ``` 87 | 88 | ​ 编译安装 89 | 90 | ``` 91 | ./autogen.sh 92 | 93 | ./configure 94 | 95 | make 96 | 97 | sudo make install 98 | 99 | // 检查版本 100 | protoc --version 101 | ``` 102 | 103 | ​ 将库加入到动态连接库的配置文件(读者也可选择通过其他的方式来实现库链接,比如环境变量) 104 | 105 | ``` 106 | sudo nano /etc/ld.so.conf.d/local.conf 107 | 108 | // 打开之后在文件中写入 109 | /usr/local/lib 110 | ``` 111 | 112 | ​ 更新动态连接库缓存 113 | 114 | ``` 115 | sudo idconfig 116 | ``` 117 | 118 | ### 安装sqlite3 119 | 120 | ​ 本项目安装的sqlite版本为sqlite3 3.37.2版本。 121 | 122 | ​ 先获取对应版本 123 | 124 | ``` 125 | wget https://www.sqlite.org/2022/sqlite-autoconf-3370200.tar.gz 126 | ``` 127 | 128 | ​ 解压源码 129 | 130 | ``` 131 | tar -xvf sqlite-autoconf-3370200.tar.gz 132 | cd sqlite-autoconf-3370200 133 | ``` 134 | 135 | ​ 编译和安装 136 | 137 | ``` 138 | ./configure --prefix=/usr/local 139 | 140 | make 141 | 142 | sudo make install 143 | ``` 144 | 145 | ​ 查看版本 146 | 147 | ``` 148 | sqlite3 --version 149 | 3.37.2 2022-01-06 13:25:41 872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5dalt1 150 | ``` 151 | 152 | ### 安装muduo库 153 | 154 | ​ 下载源码 155 | 156 | ``` 157 | git clone https://github.com/chenshuo/muduo.git 158 | ``` 159 | 160 | ​ 安装对应的依赖环境 161 | 162 | ``` 163 | sudo apt-get install libz-dev libboost-all-dev 164 | ``` 165 | 166 | ​ 运行脚本编译安装 167 | 168 | ``` 169 | unzip muduo-master.zip 170 | 171 | cd muduo-master 172 | 173 | ./build.sh 174 | 175 | ./build.sh install 176 | ``` 177 | 178 | ​ 切换编译目录 179 | 180 | ``` 181 | // 就在上级目录中的build目录下 182 | cd ../build/release-cpp11/bin 183 | 184 | // 运行程序,查看是否安装成功 185 | // 服务端 186 | ./protobuf_server 9091 187 | // 客户端 188 | ./protobuf_client 0.0.0.0 9091 189 | // 若成功运行则说明安装成功 190 | ``` 191 | 192 | ​ 头文件以及库文件的链接(muduo下载之后的头文件以及库文件不会自动加载到对应的目录或者环境变量中,需要复制到对应的目录或者加入环境变量才能编译成功) 193 | 194 | ​ 先把库文件复制到/usr/local/lib/目录下 195 | 196 | ``` 197 | // 先找到对应文件目录 198 | sudo find / -name "libmuduo_net*" 199 | // /home/jzhong/code/bag/build/release-cpp11/lib/libmuduo_net.a (说明在/home/jzhong/code/bag/build/release-cpp11/lib/)目录下 200 | 201 | // 将该目录下的所有文件复制到/usr/local/lib/ 202 | sudo cp 刚刚找到的目录/lib/*.a /usr/local/lib/ 203 | 204 | // 更新链接器缓存 205 | sudo ldconfig 206 | ``` 207 | 208 | ​ 然后把头文件复制到/usr/local/include/目录下 209 | 210 | ``` 211 | // 先找到对应的头文件目录 212 | sudo find / -name "Logging.h" 213 | // /home/jzhong/code/bag/muduo-master/muduo/base/Logging.h(将Logging.h上两级目录整个muduo目录都移动到/usr/local/include/目录下) 214 | 215 | sudo cp -r /home/jzhong/code/bag/muduo-master/muduo /usr/local/include/ 216 | ``` 217 | 218 | ​ 以上这两种方法只是我提供的一种方法,读者也可以选择其他的方法。 219 | 220 | ## 编译 221 | 222 | ​ 当前一共存在两端:客户端和服务前端,分别编译执行这两个即可,安装好以上环境之后,分别在对应路径下进行编译即可,如下: 223 | 224 | ​ 编译客户端: 225 | 226 | ![client](.\image\client.gif) 227 | 228 | ​ 编译服务器端: 229 | 230 | ![server](.\image\server.gif) 231 | 232 | ## 运行 233 | 234 | ​ 运行前,需要先运行服务前端,让其可以接收对应的连接以及请求。如下: 235 | 236 | ![1](.\image\1.png) 237 | 238 | ​ 当接收到对应的连接时会打印相关的日志。 239 | 240 | ​ 以下的测试运行将从五个方面进行:分别是用户管理、消息的发送和接收、用户数据管理、系统数据管理、订阅管理 241 | 242 | ### 用户管理 243 | 244 | ​ 用户的登陆与注册: 245 | 246 | ![image-20241224232027606](./image/image-20241224232027606.png) 247 | 248 | ​ 用户修改个人信息: 249 | 250 | ![image-20241224232242443](./image/image-20241224232242443.png) 251 | 252 | ​ 用户列表显示: 253 | 254 | ![image-20241224232429831](./image/image-20241224232429831.png) 255 | 256 | ​ 修改/删除用户: 257 | 258 | ![image-20241224232544644](./image/image-20241224232544644.png) 259 | 260 | ### 消息的发送和接收 261 | 262 | ​ 消息接收发布前的准备工作: 263 | 264 | ![image-20241224232705876](./image/image-20241224232705876.png) 265 | 266 | ![image-20241224232711477](./image/image-20241224232711477.png) 267 | 268 | ​ 消息发布用户编辑要发送的信息: 269 | 270 | ![image-20241224232849081](./image/image-20241224232849081.png) 271 | 272 | ​ 发送消息和接收消息: 273 | 274 | ![image-20241224232924486](./image/image-20241224232924486.png) 275 | 276 | ​ 查看信箱数据: 277 | 278 | ![image-20241224232919773](./image/image-20241224232919773.png) 279 | 280 | ### 用户数据管理 281 | 282 | ​ 垃圾回收(回收服务前端中无用的信息): 283 | 284 | ![image-20241224233313372](./image/image-20241224233313372.png) 285 | 286 | ​ 管理员查看/修改用户数据: 287 | 288 | ![image-20241224233331337](./image/image-20241224233331337.png) 289 | 290 | ### 系统数据管理 291 | 292 | ​ 管理员查看/修改交换机数据 293 | 294 | ![image-20241224233514017](./image/image-20241224233514017.png) 295 | 296 | ​ 管理员查看/修改队列数据 297 | 298 | ![image-20241224233522934](./image/image-20241224233522934.png) 299 | 300 | ​ 管理员查看/修改绑定关系数据 301 | 302 | ![image-20241224233540443](./image/image-20241224233540443.png) 303 | 304 | ### 订阅管理 305 | 306 | ​ 管理员查看用户的订阅 307 | 308 | ![image-20241224233846104](./image/image-20241224233846104.png) 309 | 310 | ​ 管理员删除用户的订阅 311 | 312 | ![image-20241224233850735](./image/image-20241224233850735.png) 313 | 314 | ​ 管理员修改用户的订阅 315 | 316 | ![image-20241224233855070](./image/image-20241224233855070.png) -------------------------------------------------------------------------------- /image/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/1.png -------------------------------------------------------------------------------- /image/client.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/client.gif -------------------------------------------------------------------------------- /image/image-20241224232027606.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232027606.png -------------------------------------------------------------------------------- /image/image-20241224232242443.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232242443.png -------------------------------------------------------------------------------- /image/image-20241224232429831.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232429831.png -------------------------------------------------------------------------------- /image/image-20241224232544644.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232544644.png -------------------------------------------------------------------------------- /image/image-20241224232705876.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232705876.png -------------------------------------------------------------------------------- /image/image-20241224232711477.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232711477.png -------------------------------------------------------------------------------- /image/image-20241224232849081.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232849081.png -------------------------------------------------------------------------------- /image/image-20241224232919773.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232919773.png -------------------------------------------------------------------------------- /image/image-20241224232924486.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224232924486.png -------------------------------------------------------------------------------- /image/image-20241224233313372.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233313372.png -------------------------------------------------------------------------------- /image/image-20241224233331337.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233331337.png -------------------------------------------------------------------------------- /image/image-20241224233514017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233514017.png -------------------------------------------------------------------------------- /image/image-20241224233522934.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233522934.png -------------------------------------------------------------------------------- /image/image-20241224233540443.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233540443.png -------------------------------------------------------------------------------- /image/image-20241224233846104.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233846104.png -------------------------------------------------------------------------------- /image/image-20241224233850735.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233850735.png -------------------------------------------------------------------------------- /image/image-20241224233855070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/image-20241224233855070.png -------------------------------------------------------------------------------- /image/server.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/server.gif -------------------------------------------------------------------------------- /image/图片1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jie200408/MyProject/3d95820912a69d81dc3c9439b665680817a38acf/image/图片1.png --------------------------------------------------------------------------------