代码改变世界

实用指南:项目——基于C/S架构的预约系统平台(3)

2025-11-25 09:13  tlnshuju  阅读(0)  评论(0)    收藏  举报

前言:

首先恭喜我自己!!!第一个项目初步的业务已经圆满结束

不过过程确实很凄惨....我觉得架构实现起来是最难的 往往都是跟着人家一点点码出来架构 然后一点点来回试sql的正确 感觉历经磨难...借助ai的辅助总归是把这个项目的基本业务完成了

我又稍微优化(×细分)了一下架构 给大家展示一下

ser.h

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int listenmax=10;
enum op_type{
    DL=1,
    ZC,
    CKYY,
    YD,
    CKYD,
    QXYD,
    TC
};
//mysql数据库操作类
class mysql_client{
public:
    // 默认构造函数:初始化数据库连接参数(本地数据库默认配置)
    mysql_client(){
        db_ips="127.0.0.1";
        db_username="root";
        db_dbname="project_db";
        db_passwd="770202";
    }
    // 析构函数:关闭数据库连接
    ~mysql_client(){
        mysql_close(&mysql_con);
    }
    bool mysql_connectserver();
    // 参数:tel(手机号)、passwd(密码)、name(用户名)
    bool mysql_register(const string &tel,const string &passwd,const string &name);
    bool mysql_login(const string&tel,const string &passwd,string &name);
    // 查看可预约信息:从数据库查询预约数据,存入JSON对象
    // 参数:resval(输出参数,存储查询结果)
    bool mysql_show_ticket(Json::Value&resval);
    bool mysql_subscribe_ticket(int tk_id,string tel);
    //查看我的预约,增加函数设计参数
    //取消预约,增加函数设计参数
    bool mysql_cancel_sub_ticket(int yd_id, const string& tel);
    bool mysql_show_sub_ticket(const string& tel, Json::Value& resval);
private:
    // 事务开始(用于需要原子性的操作,如预订时减库存+记录预订)
    bool mysql_user_begin();
    // 事务提交(操作成功时确认变更)
    bool mysql_user_commit();
    // 事务回滚(操作失败时撤销变更)
    bool mysql_user_rollback();
private:
    MYSQL mysql_con;
    string db_ips;
    string db_username;
    string db_dbname;
    string db_passwd;
};
//服务器监听
class socket_listen{
public:
    socket_listen(){
        sockfd=-1;
        m_port=6000;
        m_ips="127.0.0.1";
    }
    socket_listen(string ips,short port):m_ips(ips),m_port(port){
        sockfd=-1;
    }
    bool socket_init();
    int accept_client();
    void set_base(struct event_base*base){
        this->base=base;
    }
    int getsockfd()const{
        return sockfd;
    }
    struct event_base* get_base()const{
        return base;
    }
private:
    int sockfd;
    short m_port;
    string m_ips;
    struct event_base * base;
};
//客户端连接处理
class socket_con{
public:
    socket_con(int fd):c(fd){
        c_ev=NULL;
    }
    void set_ev(struct event*ev){
        c_ev=ev;
    }
    ~socket_con(){
        event_free(c_ev);
        close(c);
    }
    void recv_data();
    void send_err();
    void send_ok();
    void user_register();
    void user_login();
    void user_show_ticket();//查看预约信息
    void user_subscribe_ticket();//预订
    void user_cancel_sub_ticket();
    void user_show_sub_ticket();
private:
    int c;
    struct event* c_ev;
    Json::Value val;
    //mysql_client cli;
};

listen.cpp

#include"ser.h"
bool socket_listen::socket_init(){
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(-1==sockfd)return false;
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(m_port);
    saddr.sin_addr.s_addr=inet_addr(m_ips.c_str());
    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(-1==res){
        perror("绑定失败\n");
        close(sockfd);
        return false;
    }
    res=listen(sockfd,listenmax);
    if(res==-1)return false;
    return true;
}
int socket_listen::accept_client(){
    int c=accept(sockfd,NULL,NULL);
    return c;
}

ser.cpp

#include"ser.h"
//mysql_client
//socket_listen
//socket_con
void socket_con::send_err(){
    Json::Value res_val;
    res_val["status"]="ERR";
    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
}
void socket_con::send_ok(){
    Json::Value res_val;
    res_val["status"]="OK";
    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
}
void socket_con::user_register(){
    string tel,passwd,username;
    tel=val["user_tel"].asString();
    passwd=val["user_passwd"].asString();
    username=val["user_name"].asString();
    if(tel.empty()||passwd.empty()||username.empty()){
        send_err();
        return;
    }
    mysql_client cli;
    if(!cli.mysql_connectserver()){
        send_err();
        return;
    }
    if(!cli.mysql_register(tel,passwd,username)){
        send_err();
        return;
    }
    send_ok();
    return;
}
void socket_con::user_login(){
    string tel=val["user_tel"].asString();
    string passwd=val["user_passwd"].asString();
    string user_name;
    mysql_client cli;
    if(!cli.mysql_connectserver()){
        send_err();
        return;
    }
    if(!cli.mysql_login(tel,passwd,user_name)){
        send_err();
        return;
    }
    Json::Value res_val;
    res_val["status"]="OK";
    res_val["user_name"]=user_name;
    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
    return;
}
void socket_con::user_show_ticket(){
    Json::Value resval;
    mysql_client cli;
    if(!cli.mysql_connectserver()){
        send_err();
        return;
    }
    if(!cli.mysql_show_ticket(resval)){
        send_err();
        return;
    }
    send(c,resval.toStyledString().c_str(),strlen(resval.toStyledString().c_str()),0);
    return;
}
void socket_con::user_subscribe_ticket(){
    //client  ->  tk_id ,tel
    int tk_id=val["index"].asInt();
    string tel=val["tel"].asString();
    mysql_client cli;
    if(!cli.mysql_connectserver()){
        cout<<"connect mysql err"<recv_data();
    }
}
void SOCK_LIS_CALLBACK(int sockfd,short ev,void *arg){
    socket_listen* p=(socket_listen*)arg;
    if(p==NULL)return;
    if(ev&EV_READ){ //处理读事件
        int c=p->accept_client();
        if(c==-1)return;
        cout<<"accept:c="<get_base(),c,EV_READ|EV_PERSIST,SOCK_CON_CALLBACK,q);
        if(c_ev==NULL){
            close(c);
            delete q;
            return;
        }
        q->set_ev(c_ev);
        //添加到libevent
        event_add(c_ev,NULL);
    }
}
int main(){
    //监听套接字
    socket_listen socket_ser;
    if(!socket_ser.socket_init()){
        cout<<"socket init err!"<

mysqlconnect.cpp

#include"ser.h"
bool mysql_client::mysql_connectserver(){
    MYSQL*mysql=mysql_init(&mysql_con);
    if(mysql==NULL)return false;
    mysql=mysql_real_connect(mysql,db_ips.c_str(),db_username.c_str(),db_passwd.c_str(),db_dbname.c_str(),3306,NULL,0);
    if(mysql==NULL){
        cout<<"connect db server err"<

接下来是客户端的

cli.h

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int offset=2;
enum op_type{DL=1,ZC,CKYY,YD,CKYD,QXYD,TC};
//客户端及具体实现功能
class socket_client{
public:
    socket_client(){
        sockfd=-1;
        ips="127.0.0.1";
        port=6000;
        dl_flg=false;
        user_op=0;
        runing=true;
    }
    socket_client(string ips,short port){
        sockfd=-1;
        this->ips=ips;
        this->port=port;
        dl_flg=false;
        user_op=0;
        runing=true;
    }
    void print_info();
    ~socket_client(){
        close(sockfd);
    }
    bool connect_server();
    void user_register();
    void user_login();
    void user_show_ticket();
    void user_subscribe_ticket();
    void user_cancel_sub_ticket();
    void user_show_sub_ticket();
    void run();
private:
    string ips;
    short port;
    int sockfd;
    bool dl_flg;
    string username;
    string usertel;
    int user_op;
    bool runing;
    Json::Value m_val;
};

connect.cpp

#include"cli.h"
bool socket_client::connect_server(){
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(-1==sockfd){
        perror("create socket err!\n");
        return false;
    }
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(port);
    saddr.sin_addr.s_addr=inet_addr(ips.c_str());
    int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1){
        perror("connect ser err!\n");
        return false;
    }
    cout<<"connect to server success"<

cli.cpp

#include"cli.h"
void socket_client::print_info(){
    if(dl_flg){
        cout<<"--已登陆-------用户名:"<>user_op;
        user_op+=offset;
    }
    else{
        cout<<"---未登陆-----游客-----"<>user_op;
        if(user_op==3)user_op=TC;
    }
}
void socket_client::user_register(){
    cout<<"请输入用户手机号码:"<>usertel;
    cout<<"请输入用户名"<>username;
    string passwd,tmp;
    cout<<"请输入密码:"<>passwd;
    cout<<"请再次输入密码"<>tmp;
    if(usertel.empty()||username.empty()){
        cout<<"手机或用户名不能为空"<>tel;
    cout<<"请输入密码"<>passwd;
    if(tel.empty()||passwd.empty()){
        cout<<"帐号或密码不能为空"<>index;
    //index  有效性检查
    Json::Value val;
    val["type"]=YD;
    val["tel"]=usertel;
    val["index"]=index;
    send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0);
    char buff[256]={0};
    int n=recv(sockfd,buff,255,0);
    if(n<=0){
        cout<<"ser close"<> yd_id;
    //  构建请求JSON
    Json::Value val;
    val["type"] = QXYD;
    val["tel"] = usertel;
    val["yd_id"] = yd_id;
    send(sockfd, val.toStyledString().c_str(), strlen(val.toStyledString().c_str()), 0);
    char buff[256]={0};
    int n=recv(sockfd,buff,255,0);
    if(n<=0){
        cout<<"ser close"<

可继续优化点:

高优先级(安全与稳定性)

1. 数据完整性问题

· send/recv数据完整性
  · 实现send_all()和recv_all()函数
  · 处理部分发送/接收的情况
  · 考虑定义应用层协议(长度头 + JSON体)

2. SQL注入防护

· 预处理语句替换字符串拼接
  · 注册功能:mysql_register()
  · 登录功能:mysql_login()
  · 票务查询:mysql_show_ticket()
  · 预订功能:mysql_subscribe_ticket()

3. 输入验证完善

· 空值检查后立即返回(已发现的问题)
· 手机号格式验证(正则表达式)
· 用户名长度限制
· 整数参数范围检查

4. 资源泄漏修复

· 数据库连接管理
  · 当前:每次操作新建连接(性能差)
  · 目标:实现连接池
· 内存泄漏检查
  · socket_con对象的生命周期管理
  · MySQL结果集释放mysql_free_result()

中优先级(性能与用户体验)

5. 非阻塞IO改造

· 服务端socket设为非阻塞
· 客户端socket设为非阻塞
· 处理EAGAIN/EWOULDBLOCK错误码
· 实现IO多路复用的完整优势

6. Libevent性能优化

· 升级到Libevent2新API
· 启用ET边缘触发模式
· 配置高性能事件驱动后端

7. 数据库优化

· 连接池实现
· 为常用查询字段添加索引
· 查询结果缓存机制

8. 错误信息细化

· 区分不同错误类型:
  · 用户已存在
  · 密码错误
  · 票已售完
  · 数据库连接失败
· 返回具体错误码和描述

低优先级(代码质量与扩展性)

9. 代码结构优化

· 配置文件外部化
  · 数据库连接参数
  · 服务器端口配置
· 日志系统完善
· 统一错误处理机制

10. 安全增强

· 密码加密传输(MD5/SHA1)
· 敏感信息脱敏
· 请求频率限制

11. 协议优化

· 二进制协议替代JSON(可选)
· 数据压缩
· 心跳包机制

具体实施计划

Phase 1:安全与稳定性(预计2-3天)

```
1. 数据完整性 → 2. SQL注入防护 → 3. 输入验证 → 4. 资源泄漏
```

Phase 2:性能优化(预计3-4天)

```
5. 非阻塞IO → 6. Libevent优化 → 7. 数据库连接池
```

Phase 3:用户体验(预计1-2天)

```
8. 错误信息细化 → 9. 配置外部化
```

业务逻辑优化

· 重复查询优化:user_subscribe_ticket()中先调用了user_show_ticket()
· 事务边界细化:某些查询操作不需要事务
· 数据验证前置:客户端先做基础验证,减少服务端压力

 客户端体验

· 输入错误处理:类型转换异常处理
· 操作确认:重要操作前的确认提示
· 结果展示优化:表格格式化输出

总结:

sql注入的风险还是很大的 所以有时间需要修改一下那里。让ai预测了一下并发数量 它预测支持几十个让我有点破防 但是我压力测试了一下发现能达到一千多(甚至是因为mysql的连接量满的原因)所以还是超过我的预期的  遇到的困难很多哎 比如sql语句的描述 json的序列化反序列 还有n多的参数记不住。。。总而言之ai帮了大忙(

哎简单来说毕竟这是从0到1的跨越嘛~再多做几个玩具就能游龙了吧(应该?  第一阶段的预约系统就到这里啦~