# shared_bike **Repository Path**: wu-xianfengx/shared_bike ## Basic Information - **Project Name**: shared_bike - **Description**: 共享单车的服务端主要负责处理用户与单车之间的交互,管理单车和用户信息,处理支付,以及其他关键功能。系统采用事件驱动模型,通过发布-订阅模式实现业务逻辑层的高效运作。 - **Primary Language**: Unknown - **License**: AFL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2024-08-09 - **Last Updated**: 2024-10-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: 事件驱动架构, 发布-订阅模式, 高并发 ## README # shared_bike #### 介绍 共享单车的服务端主要负责处理用户与单车之间的交互,管理单车和用户信息,处理支付,以及其他关键功能。系统采用事件驱动模型,通过发布-订阅模式实现业务逻辑层的高效运作。 #### 软件架构 应用层协议的设计: 通信双方交换数据的格式,使用protobuf进行序列化. ![短信获取](https://foruda.gitee.com/images/1723169564597999688/0c9633b2_13404964.png "登录验证模块.png") ![登录验证](https://foruda.gitee.com/images/1723169745655008056/9d5dfaf2_13404964.png "验证模块.png") ![充值](https://foruda.gitee.com/images/1723170256647205009/79b5ebda_13404964.png "充值.png") ![充值记录查询](https://foruda.gitee.com/images/1723170280531434469/bcae8755_13404964.png "充值记录查询.png") ![余额查询](https://foruda.gitee.com/images/1723170312169212883/2c085b55_13404964.png "余额查询.png") ![骑行记录](https://foruda.gitee.com/images/1723170331564243056/223f846f_13404964.png "骑行记录.png") **设计类图:** ### 第一次迭代: ![第一次迭代](https://foruda.gitee.com/images/1723170479946876090/f94ae267_13404964.png "第一次迭代.png") **类图说明:** - NetworkInterface - 负责监听tcp连接、接收和响应客户端请求数据,其通过调用DispatchMsgService类的相关接口解析消息和事件,并派发事件 - DispatchMsgService - 负责分发消息服务模块,其实就是把外部收到的消息,转化成内部事件,也就是data->msg->event的解码过程,然后再把事件投递至线程池的消息队列,由线程池调用其process 方法对事件进行处理,最终调用每个event的handler方法来处理event,此时每个event handler需要subscribe该event后才会被调用到. - thread_pool_t - 线程池,实现高并发处理各种事件(用户、单车事件) - iEventHandler - 事件处理器 , 负责处理相关的事件(如:用户、单车事件等) - iEvent - 请求事件实体 ### 第二次迭代: ![第二次迭代](https://foruda.gitee.com/images/1723170502746578948/8a7b0c6a_13404964.png "第二次迭代.png") **新增类的说明:** - MysqlConnection 用于连接数据库,提供数据库访问接口 - SqlTables 用于创建表 - BusinessProcessor 负责协调处理事务,在构造的时候会创建数据库表 ,和事件处理器。 #### 使用说明、环境准备 1. protobuf 安装 - apt-get install autoconf automake libtool curl make g++ unzip - git clone https://github.com/protocolbuffers/protobuf.git - cd protobuf - git submodule update --init --recursive - ./autogen.sh - ./configure - make - make check - sudo make install - sudo ldconfig 2. log4cpp - wget https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz - 我这里的网址已经不可用了. - tar xzvf log4cpp-1.1.3.tar.gz - cd log4cpp-1.1.3 - ./configure #这里可以指定安装路径 - make - make install 3. libevent - libevent官网 http://libevent.org/ - https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz - tar zxvf libevent-2.1.12-stable.tar.gz - cd libevent-2.1.12-stable - ./configure --disable-openssl - make - make install 4. mysqlclient、mysqlservice - sudo apt-get install libmysqlclient-dev - sudo apt-get install mysql-server 5. iniparser - wget https://codeload.github.com/ndevilla/iniparser/tar.gz/refs/tags/v4.1 -O iniparserv4.1.tar.gz - tar -zxvf iniparserv4.1.tar.gz #### protobuf 定义 message 所有的message必须定义到一个文件中,且文件的后缀名为.proto。例如我们定义的 bike.proto文件 ``` syntax = "proto2"; package tutorial; message mobile_request { required string mobile = 1; } message mobile_response { required int32 code = 1; //响应代号 required int32 icode = 2; //验证码 optional string data = 3; //失败原因 } message login_request { required string mobile = 1; // 手机号码 required int32 icode = 2; // 验证码 } message login_response { required int32 code = 1; // 响应代号 optional string desc = 2; // 验证码 } message recharge_request { required string mobile = 1; // 手机号码 required int32 amount = 2; // 充值金额 } message recharge_response { required int32 code = 1; // 响应代号 optional string desc = 2; // 验证码 required int32 balance = 3; // 最新的余额 } message account_balance_request { required string mobile = 1; } message account_balance_response { required int32 code = 1; // 响应代号 optional string desc = 2; // 验证码 required int32 balance = 3; } message list_account_records_request { required string mobile = 1; } message list_account_records_response { required int32 code = 1; // 响应代号 optional string desc = 2; // 验证码 message account_record { required int32 type = 1; // 0 : 骑行消费, 1 : 充值, 2 : 退款 required int32 limit = 2; // 消费或者充值金额 required uint64 timestamp = 3; // 记录发生时的时间戳 } repeated account_record records = 3; } message list_travel_records_request { required string mobile = 1; } message list_travel_records_response { required int32 code = 1; // 响应代号 optional string desc = 2; // 验证码 message travel_record { required uint64 stm = 1; // start timestamp required uint32 duration = 2; // 骑行时长 required uint32 amount = 3; // 所耗金额 } required double mileage = 3; // 里程 required double discharge = 4; // 排放 required double calorie = 5; // 卡路里 repeated travel_record records = 6; } ``` 编译: 编译语法: - protoc -I=$SRC_DIR --cpp_out=$DST_DIR bike.proto - SRC_DIR 表示proto文件所在的目录,cpp_out指定了生成的代码的路径, bike.proto指proto文件名。 - protoc -I=./ --cpp_out=./ bike.proto - 这样在当前目录生成了bike.pb.cc和bike.pb.h两个文件。 编译生成的c++文件 - g++ -std=c++11 example.cc bike.pb.cc -lprotobuf **应用protobuf** 把生成了protocol.pb.cc和protocol.pb.h加入到工程,那么接着就是调用一些API,完成序列化和反序列化 **API说明:** https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message ### 配置日志的配置文件 log.conf ``` #定义Root category 的属性 log4cpp.rootCategory = DEBUG , RootLog #定义 RootLog 属性 log4cpp.appender.RootLog = RollingFileAppender log4cpp.appender.RootLog.layout = PatternLayout #log4cpp.appender.RootLog.layout.ConversionPattern =%d{% m-%d %H:%M:%S %l}[%t][%p]%m%n log4cpp.appender.RootLog.layout.ConversionPattern=%d{%m-%d %H:%M:%S %l}[%t][%p]%m%n log4cpp.appender.RootLog.fileName=/var/log/shared_bike.log log4cpp.appender.RootLog.maxFileSize=268435456 #256MB log4cpp.appender.RootLog.fileNamePattern =shared_bike_%i.log log4cpp.appender.RootLog.maxBackupIndex=256 ``` ### 数据库设计 ![用户信息](%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF.png) ![自行车信息](%E8%87%AA%E8%A1%8C%E8%BD%A6%E4%BF%A1%E6%81%AF.png)