Linux服务器项目-共享单车
一、应用层协议设计
- 通信双方交换数据的格式与顺序
- 通信双方应该采取的动作
- 使用 protobuf 序列化
- 短信获取
获取短信请求:mobile_resquest
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
mobile | string | required | 手机号码,必须为大陆手机号。取11位数字 |
获取短信响应:mobile_response
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
code | int32 | required | 响应代号:200表示成功。400表示失败。 |
icode | int32 | required | 验证码 |
desc | string | optional | 失败时描述原因(可选) |
- 登录验证
登录请求:login_request
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
mobile | string | required | 手机号码,必须为大陆手机号。取11位数字 |
icode | int32 | required | 验证码 |
登录响应:login_response
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
code | int32 | required | 响应代号:200表示成功。400表示失败。 |
desc | string | optional | 失败时描述失败原因(可选) |
- 充值
充值请求:recharge_request
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
mobile | string | required | 手机号码,必须为大陆手机号。取11位数字 |
amount | int32 | required | 充值数量 |
充值响应:recharge_response
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
code | int32 | required | 响应代号:200表示成功。400表示失败。 |
desc | string | optional | 失败时描述失败原因(可选) |
balance | int32 | required | 最新余额 |
- 查询余额
查询余额请求:account_balance_request
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
mobile | string | required | 手机号码,必须为大陆手机号。取11位数字 |
余额查询响应:account_balance_response
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
code | int32 | required | 响应代号:200表示成功。400表示失败。 |
desc | string | optional | 失败时描述失败原因(可选) |
balance | int32 | required | 余额(失败时置为-1) |
- 查询充值记录
充值记录查询请求:list_account_records_request
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
mobile | string | required | 手机号码,必须为大陆手机号。取11位数字 |
充值记录查询请求:list_account_records_response
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
code | int32 | required | 响应代号:200表示成功。400表示失败。 |
desc | string | optional | 失败时描述失败原因(可选) |
records | account_record | repeated | 类型见下表 |
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
type | int32 | required | 0 : 骑行消费, 1 : 充值, 2 : 退款 |
limit | int32 | required | 消费或者充值金额 |
timestamp | uint64 | repeated | 记录发生时的时间戳 |
- 骑行记录查询
骑行记录查询请求:list_travel_records_request
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
mobile | string | required | 手机号码,必须为大陆手机号。取11位数字 |
骑行记录查询响应: list_travel_records_response
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
code | int32 | required | 响应代号:200表示成功。400表示失败。 |
desc | string | optional | 失败时描述失败原因(可选) |
records | travel_record | repeated | 类型见下表 |
mileage | double | required | 骑行里程 |
discharge | double | required | 排放 |
calorie | double | required | 卡路里 |
字段名 | 类型 | 属性 | 描述 |
---|---|---|---|
stm | uint64 | required | 开始骑行时的事件戳 |
duration | int32 | required | 骑行时长 |
amount | uint32 | repeated | amount |
二、使用 protobuf 将如上协议结构化数据
protobuf的使用参考:谷歌protobuf(Protocol buffers)的使用
proto源码如下:
syntax = "proto2";
package shared_bike;
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;
}
三、开发工具:Visual Studio 2019
VS2019下写Linux代码参考:使用 Visual Studio 2019 开发 Linux 项目
四、第一次迭代
1. 目标
实现libevent 和线程池的整合,结合发布订阅者模式实现业务逻辑层的代码框架,能够实现获取短信请求的模拟响应(不包含数据库的具体实现)。
2. 设计类图
- NetworkInterface - 负责监听 tcp连接、接收和响应客户端请求数据,其通过调用 DispatchMsgService类的相关接口解析消息和事件,并派发事件。
- DispatchMsgService - 负责分发消息服务模块,其实就是把外部收到的消息,转化成内部事件,也就是data->msg->event的解码过程,然后再把事件投递至线程池的消息队列,由线程池调用其process 方法对事件进行处理,最终调用每个event的handler方法来处理event,此时每个event handler需要subscribe该event后才会被调用到。
- thread_pool_t - 线程池,实现高并发处理各种事件(用户、单车事件)。
- iEventHandler - 负责处理相关的事件(如:用户、单车事件等)。
- iEvent - 请求事件实体。
3. 第一次迭代源码
链接( 密码:shared):共享单车项目第一次迭代源码
五、第二次迭代
1. 目标
实现后台数据库访问模块的框架,能够实现验证请求并响应(支持数据库操作)
2. 设计类图
- MysqlConnection - 数据库访问接口
- SqlTables - 负责数据库表的创建
- BusinessProcessor - 负责协调处理事务
3. 数据库表设计
- 用户信息
字段名 | 类型 | 是否为空 | 默认值 | 主、外键 | 备注 |
---|---|---|---|---|---|
id | int(16) | NOT | 1, 自增长 | PK | 用户ID |
username | varchar(128) | NOT | 用户名:英文字符、数字和特殊符号的组合 | ||
mobile | varchar(16) | NOT | ‘13000000000’ | 手机号 | |
registertm | timestamp | NOT | 当前时间 | 注册时间 | |
money | int(4) | NOT | 0 | 账户余额 |
表其他信息:
名称 | 类型 | 备注 |
---|---|---|
mobile_index(mobile) | index | 索引 |
- 自行车信息
字段名 | 类型 | 是否为空 | 默认值 | 主、外键 | 备注 |
---|---|---|---|---|---|
id | int | NOT | 自增长 | PK | 单车ID |
devno | int | NOT | 单车编号 | ||
status | tinyint(1) | NOT | 0 | 单车状态:0(停止)、1(骑行中)、2(损坏)、3(维修中) | |
trouble | int | NOT | 0 | 损坏类型编号 | |
tmsg | varchar(256) | NOT | “” | 损坏原因描述 | |
latitude | double(10,6) | NOT | 0 | 纬度 | |
longitude | double(10,6) | NOT | 0 | 经度 |
表其他信息:
名称 | 类型 | 备注 |
---|---|---|
unique(devno) | PRIMARY KEY | 唯一键约束 |
4. 第二次迭代源码
链接( 密码:shared):共享单车项目第二次迭代源码