【C++标准项目】C++基于protobuf的发布订阅式消息队列(篇一):项目概述+环境搭建

1. 项目介绍

我们之前学过阻塞队列(BlockingQueue),它最典型的应用场景就是实现生产者消费者模型 。生产者消费者模型是后端开发中非常常用的编程方式,它带来诸多好处:

  • 解耦 ------ 生产者与消费者互不依赖
  • 支持并发 ------ 生产和消费可以并行推进
  • 支持忙闲不均 ------ 双方处理速率不一致时,队列充当缓冲区
  • 削峰填谷 ------ 突发流量先入队,后端按自身能力匀速消费

在实际的后端开发中,尤其是分布式系统里,跨主机 使用生产者消费者模型也是非常普遍的需求。为此,我们通常会把队列封装成一个独立的服务程序,并赋予它更丰富的功能 ------ 这类服务程序就称为消息队列(Message Queue,MQ)。

与进程内的阻塞队列相比,MQ 额外具备网络通信 、消息持久化 和消息路由能力。

市面上成熟的消息队列非常多:

  • RabbitMQ
  • Kafka
  • RocketMQ
  • ActiveMQ

其中 RabbitMQ 知名度高、功能强大、使用广泛。本项目就仿照 RabbitMQ,模拟实现一个简单的消息队列。


2. 开发环境

  • 操作系统:Linux(CentOS 7.6 / Ubuntu 22.04)
  • 编辑器:VSCode / Vim
  • 编译调试:g++ / gdb
  • 构建工具:Makefile

3. 技术选型

  • 开发主语言:C++
  • 序列化框架:Protobuf 二进制序列化
  • 网络通信 :自定义应用层协议
    • 原生 socket:可控性最强,但需要自行处理 IO 多路复用、缓冲区管理等细节,复杂度较高
    • muduo 库:封装了 TCP 长连接,采用 epoll 事件驱动模式,能更方便地实现高并发服务器与客户端
  • 数据存储:SQLite3
  • 单元测试框架:GTest

4.环境搭建

Ubuntu22.04 环境搭建

1.安装 wget(一般情况下默认会自带)

bash 复制代码
sudo apt-get install wget

2.更换国内软件源

先备份原来的/etc/apt/source.list 文件

因为我没有下载vim编辑器,所以我先下载:

备份:

这个是我vim前的结果:

添加软件源文件内容:

逐项检查都通过:

检查项 结果
代号 jammy 全程一致
清华源 换好了
deb-src 已注释 正确(日常不需要)
main / restricted / universe / multiverse 齐全
updates / backports 齐全

但有一处要改:security 源还是国外的

看你文件最后几行:

代码块

bash 复制代码
deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
deb http://security.ubuntu.com/ubuntu/ jammy-security universe
deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse

security.ubuntu.com是 Ubuntu 官方安全更新源,服务器在国外 ,国内访问同样很慢。清华源是有 jammy-security 镜像的,应该一起换掉。

改法(两步)

第 1 步:先在 vim 里保存退出

代码块

bash 复制代码
按 Esc
输入 :wq
按回车

第 2 步:一条命令替换

bash 复制代码
sudo sed -i 's|http://security.ubuntu.com/ubuntu|https://mirrors.tuna.tsinghua.edu.cn/ubuntu|g' /etc/apt/sources.list

确认改对了:

bash 复制代码
grep security /etc/apt/sources.list

新增完毕后,更新源

bash 复制代码
sudo apt-get update

3.安装 lrzsz 传输工具


4.安装编译器


5.安装项目构建工具 make


6.安装调试器


7.安装 git


8.安装 cmake


9.安装 Protobuf

  • A.安装 Protobuf 依赖库
bash 复制代码
sudo apt-get install autoconf automake libtool curl unzip gzip
#验证
which unzip gzip autoconf automake libtool curl

  • B.下载源码
bash 复制代码
wget https://gitee.com/qigezi/bitmq/raw/master/mqthird/protobuf-all-3.20.2.tar.gz

  • C.编译安装
bash 复制代码
# 解压缩
tar -zxf protobuf-all-3.20.2.tar.gz

# 切换目录
cd protobuf-3.20.2/

# 如果下载的是具体的某一门语言,不需要执行这一步
./autogen.sh

# 配置安装路径 默认安装在 /usr/local 目录
./configure

# 开始编译 15 分钟左右
make

# 开始安装, 需要 root 权限
sudo make install

# 确认是否安装成功
protoc --version
# 期望输出:libprotoc 3.20.2

当我在查看版本的时候它这里报错了:

这是经典问题:库装上了,但系统还找不到它

报错含义:

bash 复制代码
protoc: error while loading shared libraries: libprotoc.so.31: cannot open shared object file

protoc 是可执行文件 ,但它运行时还要加载动态链接库 libprotoc.so.31。这两个东西安装后是分开放的:

文件 位置
protoc(可执行文件) /usr/local/bin/protoc
libprotoc.so.31(动态库) /usr/local/lib/libprotoc.so.31

系统运行时要去"动态库搜索路径"里找 .so 文件。ldconfig 就是用来重建这个搜索缓存的。

先诊断:库到底装上没

情况 A:有输出(能看到 libprotoc.so.31)

说明库装好了,只是缓存没刷新。跑:

bash 复制代码
sudo ldconfig
protoc --version

情况 B:无输出 / No such file

说明 sudo make install 没成功。重跑:

bash 复制代码
cd ~/protobuf-3.20.2
sudo make install
sudo ldconfig
protoc --version

如果 ldconfig 之后还是报同样的错

说明 /usr/local/lib 不在默认搜索路径里,手动加进去:

bash 复制代码
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/protobuf.conf
sudo ldconfig
protoc --version

这三条就等价于教程里说的「修改 /etc/ld.so.conf,添加 /usr/local/lib/」,只是更规范的做法是单独写一个 conf 文件,而不是直接改主配置文件。


  • 若安装后的库存放于 /usr/local/lib 中, 导致运行程序时默认检索不到,则可以修改 /etc/ld.so.conf 文件,添加库文件路径到其中
  • 修改完毕后,加载配置文件

ldconfig:读取清单,生成缓存,让系统立刻识别新库路径


  • D.测试验证

第 1 步:写 contacts.proto

bash 复制代码
syntax = "proto3";
package contacts;

message PeopleInfo {
  string name = 1;
  int32 age = 2;
}

第 2 步:编译成 C++ 代码

bash 复制代码
protoc --cpp_out=./ contacts.proto
  • protoc:protobuf 的编译器
  • --cpp_out=./:生成 C++ 代码,输出目录是当前文件夹 ./
  • contacts.proto:你写的协议描述文件

执行完这条命令,自动产出 2 个文件:

  1. contacts.pb.h:头文件(类声明)
  2. contacts.pb.cc:源文件(类实现)

第 3 步:写 test.cc

bash 复制代码
#include <iostream>
#include "contacts.pb.h"     // 引入编译生成的头文件
using namespace std;

int main() {
    string people_str;

    // 序列化
    {
        // .proto 文件声明的 package,通过 protoc 编译后,
        // 会为编译生成的 C++ 代码声明同名的命名空间
        contacts::PeopleInfo people;
        people.set_age(20);
        people.set_name("张珊");
        // 调用序列化方法,将序列化后的二进制序列存入 string 中
        if (!people.SerializeToString(&people_str)) {
            cout << "序列化联系人失败." << endl;
        }
        // 打印序列化结果
        cout << "序列化后的 people_str: " << people_str.size() << endl;
    }

    // 反序列化
    {
        contacts::PeopleInfo people;
        // 调用反序列化方法,读取 string 中存放的二进制序列,并反序列化出对象
        if (!people.ParseFromString(people_str)) {
            cout << "反序列化出联系人失败." << endl;
        }
        // 打印结果
        cout << "Parse age: " << people.age() << endl;
        cout << "Parse name: " << people.name() << endl;
    }
    return 0;
}

第 4 步:编译运行

bash 复制代码
g++ -std=c++11 test.cc contacts.pb.cc -o test -lprotobuf
./test

10.安装 Muduo

bash 复制代码
 下载源码  →  装依赖  →  修复 protorpc  →   编译安装  →  验证
  • A.下载源码
bash 复制代码
cd ~/code
git clone https://github.com/chenshuo/muduo.git

GitHub 慢就用备用地址:

bash 复制代码
cd ~/code
wget https://gitee.com/hansionz/mq/raw/master/resource/muduo-master.zip
unzip muduo-master.zip

  • B. 安装依赖环境

    sudo apt install -y libz-dev libboost-all-dev


  • C.修复 protorpc

    muduo/net/protorpc/CMakeLists.txt

这一步是"条件步骤"------只有 D 编译报错了才需要改。


  • D.编译安装
bash 复制代码
cd muduo-master          # 或 muduo
./build.sh
./build.sh install

  • E.验证
bash 复制代码
cd build/release-cpp11/bin
./protobuf_server 9091              # 终端 1
./protobuf_client 0.0.0.0 9091      # 终端 2

看到 Jump! Win! = 成功。

目录保持一致:


11.安装 SQLite3

bash 复制代码
# 安装sqlite3运行库 + C/C++开发头文件
sudo apt-get install sqlite3 libsqlite3-dev

# 验证安装是否成功
sqlite3 --version

12.安装 Gtest

bash 复制代码
sudo apt-get install libgtest-dev

测试 GTest 是否安装成功

• 编写测试代码

  • 编译源文件以及运行可执行文件

5.参考文档

a.AMQP 协议

  • AMQP Part I AMQP详解-CSDN博客

    消息队列协议入门,理解 RabbitMQ 的 Exchange / Queue / Binding 模型。


b.ProtoBuf 的使用与原理


c.GTest


d.muduo


6.小结

本篇完成了消息队列项目的全部准备工作:从项目定位、技术选型,到一整套开发环境落地。

环境搭建清单

组件 版本 安装方式
1 wget 系统自带 ---
2 软件源 清华镜像(jammy) 手动配置
3 lrzsz --- apt
4 gcc / g++ 11.4.0 apt
5 make 4.x apt
6 gdb 12.1 apt
7 git 2.34.1 apt
8 cmake 3.22.1 apt
9 Protobuf 3.20.2 源码编译
10 Muduo master 源码编译
11 SQLite3 apt 版本 apt
12 GTest apt 版本 apt

三个值得记住的点

  1. 软件源必须匹配系统代号 (22.04 = jammy)。网上大量教程是 20.04 时代写的,照抄 focal 会把系统搞坏。
  2. 云服务器不用换源。腾讯云 / 阿里云出厂就配好了内网镜像,比公网源更快,还不计流量。
  3. Protobuf 和 Muduo 必须源码编译。apt 源里的版本不匹配,且 muduo 根本没有 apt 包。

验证结果

检查项 命令 预期
Protobuf protoc --version libprotoc 3.20.2
Muduo + Protobuf 跑 protobuf_server / protobuf_client 客户端打印 Jump! Win!
SQLite3 sqlite3 --version 输出版本号
GTest ./gtest [ PASSED ] 1 test.

Muduo 那一步最有价值------它用 muduo 做网络、protobuf 做序列化,跑通就说明整个技术栈(网络 + 序列化)已经就位。

相关推荐
今年下半年16 小时前
【Spring Boot】多种存储文件(FastDFS / MinIO / 阿里云 OSS)接入设计说明(附源码)
spring boot·分布式·中间件·简单工厂模式·策略模式
ShineWinsu17 小时前
对于Redis:string类型的解析
java·c++·redis·分布式·缓存·面试·string
仍然.1 天前
RabbitMQ---可靠性传输
网络·分布式·rabbitmq
灯澜忆梦1 天前
【RabbitMQ #13】 | 延迟消息
分布式·rabbitmq·ruby
青山木1 天前
秒杀系统设计(二):数据正确性——防超卖、分布式锁与一人一单
分布式·后端·mysql·中间件·架构
weixin_424183611 天前
开放—封闭原则实战(下):基于策略的流程编排与编译期多态
c++·分布式·系统架构
frjc2 天前
分布式事务:场景与选型决策表
分布式
GISMagic2 天前
5.《Designing Data-Intensive Applications》:系统设计与分布式能力提炼
分布式·ai coding
需要8262 天前
分布式 ID 生成:雪花算法、号段模式与时钟回拨
分布式·算法