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

前言:

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

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

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

ser.h

cpp 复制代码
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<string>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<event.h>
#include<jsoncpp/json/json.h>
#include<mysql/mysql.h>

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

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

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"<<endl;
        send_err();
        return;
    }
    if(!cli.mysql_subscribe_ticket(tk_id,tel)){
        send_err();
        return;
    }
    send_ok();
    return;
}

void socket_con::user_cancel_sub_ticket(){
    string tel = val["tel"].asString();
    int yd_id = val["yd_id"].asInt();

    Json::Value resval;  // 存储要返回给客户端的结果
    mysql_client cli;    // 数据库操作实例
    if (!cli.mysql_connectserver()) {
        send_err();
        return;
    }
    if (!cli.mysql_cancel_sub_ticket(yd_id,tel)) {
        send_err();
        return;
    }
    resval["status"] = "OK";  
    send(c, resval.toStyledString().c_str(), strlen(resval.toStyledString().c_str()), 0);

}

void socket_con::user_show_sub_ticket(){
    string tel = val["tel"].asString();

    Json::Value resval;  // 存储要返回给客户端的结果
    mysql_client cli;    // 数据库操作实例
    if (!cli.mysql_connectserver()) {
        send_err();
        return;
    }
    if (!cli.mysql_show_sub_ticket(tel, resval)) {
        send_err();
        return;
    }
    send(c, resval.toStyledString().c_str(), strlen(resval.toStyledString().c_str()), 0);
}


void socket_con::recv_data(){
    char buff[256]={0};
    int n=recv(c,buff,255,0);
    if(n<=0){
        cout<<"client close"<<endl;
        delete this;
        return;
    }

    //测试
    cout<<"recv:"<<buff<<endl;

    Json::Reader Read;
    if(!Read.parse(buff,val)){
        cout<<"recv_data:解析json失败"<<endl;
        send_err();
        return;
    }
    int ops=val["type"].asInt();
    switch(ops){
                case DL://登陆
                user_login();
                break;
                case ZC://注册
                user_register();
                break;
                case CKYY://查看预约
                user_show_ticket();
                break;
                case YD://预订
                user_subscribe_ticket();
                break;
                case QXYD://取消预订
                user_cancel_sub_ticket();
                break;
                case CKYD://查看预订
                user_show_sub_ticket();
                break;
                case TC://退出
                break;
            default:
            cout<<"输入无效"<<endl;
            break;
    }
    //解析
   
}


//callback
void SOCK_CON_CALLBACK(int fd,short ev,void *arg){
    socket_con*q=(socket_con*)arg;
    if(ev&EV_READ){
        q->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="<<c<<endl;

        socket_con *q=new socket_con(c);
        struct event*c_ev=event_new(p->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!"<<endl;
        exit(1);
    }
    //创建libevent base
    struct event_base*base=event_init();
    if(base==NULL){
        cout<<"base null"<<endl;
        exit(1);
    }

    //设置socket_listen中的libevent中的base
    socket_ser.set_base(base);

    //添加sockfd到libevent
    struct event*sock_ev=event_new(base,socket_ser.getsockfd(),EV_READ|EV_PERSIST,SOCK_LIS_CALLBACK,&socket_ser);
    event_add(sock_ev,NULL);
    //启动事件循环
    event_base_dispatch(base);//select poll epoll
    //释放资源
    event_free(sock_ev);
    event_base_free(base);


    return 0;
}

mysqlconnect.cpp

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"<<endl;
        return false;
    }
    return true;
}


bool mysql_client::mysql_register(const string &tel,const string &passwd,const string &name){
    //insert into user_info values(0,'13200000000','小王','123456',1);
    string sql=string("insert into user_info values(0,'")+tel+string("','")+name+string("','")+passwd+string("',1)");
    if(mysql_query(&mysql_con,sql.c_str())!=0)return false;
    return true;
}



bool mysql_client::mysql_login(const string&tel,const string &passwd,string &name){
    //select username,passwd from user_info where tel=15502639510;
    string sql1=string("select username,passwd from user_info where tel=")+tel;
    if(mysql_query(&mysql_con,sql1.c_str())!=0){
        return false;
    }

    MYSQL_RES*r=mysql_store_result(&mysql_con);
    if(r==NULL)return false;
    int num=mysql_num_rows(r);//获取结果集有多少行,0行就是为查询到,意味着该用户没有注册
    if(num==0){
        mysql_free_result(r);
        return false;
    }
    MYSQL_ROW row=mysql_fetch_row(r);

    name=row[0];
    string password=row[1];

    if(password.compare(passwd)!=0)return false;

    mysql_free_result(r);
    return true;

}




bool mysql_client::mysql_show_ticket(Json::Value &resval){
    string sql="select tk_id,addr,max,num,use_date from ticket_info";
    if(mysql_query(&mysql_con,sql.c_str())!=0){
        cout<<"show ticket err"<<endl;
        return false;
    }
    MYSQL_RES*r=mysql_store_result(&mysql_con);
    if(r==NULL)return false;

    int n=mysql_num_rows(r);
    if(n==0){
        resval["status"]="OK";
        resval["num"]=0;
        return true;
    }

    resval["status"]="OK";
    resval["num"]=n;

    for(int i=0;i<n;i++){
        MYSQL_ROW row=mysql_fetch_row(r);
        Json::Value tmp;
        tmp["tk_id"]=row[0];
        tmp["add"]=row[1];
        tmp["max"]=row[2];
        tmp["num"]=row[3];
        tmp["use_date"]=row[4];
        resval["arr"].append(tmp);
    }
    return true;
}




bool mysql_client::mysql_user_begin(){
    if(mysql_query(&mysql_con,"begin")!=0){
        return false;
    }
    return true;
}




bool mysql_client::mysql_user_commit(){
    if(mysql_query(&mysql_con,"commit")!=0){
        return false;
    }
    return true;
}



bool mysql_client::mysql_user_rollback(){
    if(mysql_query(&mysql_con,"rollback")!=0){
        return false;
    }
    return true;
}





bool mysql_client::mysql_subscribe_ticket(int tk_id,string tel){
    mysql_user_begin();//启动事务
    string s1=string("select max,num from ticket_info where tk_id=")+to_string(tk_id);
    if(mysql_query(&mysql_con,s1.c_str())!=0){
        cout<<"查询max,num失败"<<endl;
        mysql_user_rollback();
        return false;
    }
    MYSQL_RES*r=mysql_store_result(&mysql_con);
    if(r==NULL){
        cout<<"获取结果集失败"<<endl;
        mysql_user_rollback();
        return false;
    }

    int Num=mysql_num_rows(r);
    if(Num!=1){
        cout<<"记录行不为一"<<endl;
        mysql_user_rollback();
        return false;
    }

    MYSQL_ROW row=mysql_fetch_row(r);
    string str_max=row[0];//总票数
    string str_num=row[1];//当前已订票数
    int tk_max=atoi(str_max.c_str());
    int tk_num=atoi(str_num.c_str());
    if(tk_max<=tk_num){
        cout<<"没有可用的票"<<endl;
        mysql_user_rollback();
        return false;
    }
    tk_num++;

    string s2=("update ticket_info set num=")+ to_string(tk_num)+ string(" where tk_id=")+to_string(tk_id);
    if(mysql_query(&mysql_con,s2.c_str())!=0){
        cout<<"修改预订票数失败"<<endl;
        mysql_user_rollback();
        return false;
    }

    //sub_ticket
    string s3=string("insert into sub_ticket values(0,")+to_string(tk_id)+string(",'")+tel+string("',now())");
    if(mysql_query(&mysql_con,s3.c_str())!=0){
        cout<<"存入预订信息失败"<<endl;
        mysql_user_rollback();
        return false;
    }


    mysql_user_commit();
    return true;

}


bool mysql_client::mysql_cancel_sub_ticket(int yd_id, const string& tel){
    mysql_user_begin();  // 开启事务

    // 步骤1:查询该预约对应的tk_id(用于更新库存)
    string sql_query = "SELECT tk_id FROM sub_ticket WHERE yd_id = " + to_string(yd_id) + " AND tel = '" + tel + "'";
    if (mysql_query(&mysql_con, sql_query.c_str()) != 0) {
        cout << "查询tk_id失败:" << mysql_error(&mysql_con) << endl;
        mysql_user_rollback();
        return false;
    }
    MYSQL_RES* res = mysql_store_result(&mysql_con);
    if (res == NULL || mysql_num_rows(res) == 0) {
        cout << "未找到该预约记录(yd_id=" << yd_id << ",tel=" << tel << ")" << endl;
        mysql_free_result(res);
        mysql_user_rollback();
        return false;
    }
    MYSQL_ROW row = mysql_fetch_row(res);
    int tk_id = atoi(row[0]);  // 获取tk_id
    mysql_free_result(res);

    // 步骤2:更新ticket_info的库存(num-1)
    string sql_update = "UPDATE ticket_info SET num = num - 1 WHERE tk_id = " + to_string(tk_id);
    if (mysql_query(&mysql_con, sql_update.c_str()) != 0) {
        cout << "更新库存失败:" << mysql_error(&mysql_con) << endl;
        mysql_user_rollback();
        return false;
    }

    // 步骤3:删除sub_ticket中对应的预约记录(这一步之前漏掉了!)
    string sql_delete = "DELETE FROM sub_ticket WHERE yd_id = " + to_string(yd_id) + " AND tel = '" + tel + "'";
    if (mysql_query(&mysql_con, sql_delete.c_str()) != 0) {
        cout << "删除预约记录失败:" << mysql_error(&mysql_con) << endl;
        mysql_user_rollback();  // 失败则回滚
        return false;
    }

    int affected = mysql_affected_rows(&mysql_con);
    if (affected <= 0) {
        cout << "未删除任何记录(yd_id不存在或tel不匹配)" << endl;
        mysql_user_rollback();  // 回滚之前的库存更新
        return false;
    }

    // 所有步骤成功,提交事务
    mysql_user_commit();
    return true;
}



bool mysql_client::mysql_show_sub_ticket(const string& tel, Json::Value& resval){
    mysql_user_begin();
    string sql = "SELECT "
                 "sub_ticket.yd_id, sub_ticket.tk_id, ticket_info.addr, ticket_info.use_date, sub_ticket.curr_time "
                 "FROM sub_ticket "
                 "JOIN ticket_info ON sub_ticket.tk_id = ticket_info.tk_id "
                 "WHERE sub_ticket.tel = '" + tel + "'";  // 只查当前用户的
    if (mysql_query(&mysql_con, sql.c_str()) != 0) {
        cout << "查询我的预约失败:" << mysql_error(&mysql_con) << endl;
        mysql_user_rollback();
        return false;
    }
    // 处理结果集
    MYSQL_RES* r = mysql_store_result(&mysql_con);
    if (r == NULL){
        mysql_user_rollback();
        return false;
    }

    int num = mysql_num_rows(r);  // 该用户的预约总数
    resval["status"] = "OK";
    resval["num"] = num;

    // 遍历结果,存入JSON数组
    for (int i = 0; i < num; i++) {
        MYSQL_ROW row = mysql_fetch_row(r);
        Json::Value tmp;
        tmp["yd_id"] = row[0];    // 预约记录ID(sub_ticket.yd_id)
        tmp["tk_id"] = row[1];    // 项目编号(ticket_info.tk_id)
        tmp["addr"] = row[2];     // 预约地点(ticket_info.addr)
        tmp["use_date"] = row[3]; // 可使用日期(ticket_info.use_date)
        tmp["curr_time"] = row[4];// 预约时间(sub_ticket.curr_time)
        resval["arr"].append(tmp);
    }
    mysql_free_result(r);  
    mysql_user_commit();
    return true;
}

接下来是客户端的

cli.h

cpp 复制代码
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<string>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<jsoncpp/json/json.h>
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

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"<<endl;
    return true;
}

cli.cpp

cpp 复制代码
#include"cli.h"


void socket_client::print_info(){
    if(dl_flg){
        cout<<"--已登陆-------用户名:"<<username<<"-------"<<endl;
        cout<<"1:查看预约   2:预订  3: 查看我的预约  4:取消预约  5:退出"<<endl;
        cout<<"-------------------------------------------------"<<endl;
        cout<<"请输入选项编号:"<<endl;
        cin>>user_op;
        user_op+=offset;
    }
    else{
        cout<<"---未登陆-----游客-----"<<endl;
        cout<<"1:登陆   2:注册  3: 退出 "<<endl;
        cout<<"-----------------"<<endl;
        cout<<"请输入选项编号:"<<endl;
        cin>>user_op;
        if(user_op==3)user_op=TC;
    }
}


void socket_client::user_register(){
    cout<<"请输入用户手机号码:"<<endl;
    cin>>usertel;
    cout<<"请输入用户名"<<endl;
    cin>>username;
    string passwd,tmp;
    cout<<"请输入密码:"<<endl;
    cin>>passwd;
    cout<<"请再次输入密码"<<endl;
    cin>>tmp;
    if(usertel.empty()||username.empty()){
        cout<<"手机或用户名不能为空"<<endl;
        return;
    }
    if(passwd.compare(tmp)!=0){
        cout<<"密码不一致"<<endl;
        return;
    }
    Json::Value val;
    val["type"]=ZC;
    val["user_tel"]=usertel;
    val["user_name"]=username;
    val["user_passwd"]=passwd;
    send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0);
    
    char buff[256]={0};
    if(recv(sockfd,buff,255,0)<=0){
        cout<<"ser close"<<endl;
        return;
    }
    val.clear();
    Json::Reader Read;
    if(!Read.parse(buff,val)){
        cout<<"json 解析失败"<<endl;
        return;
    }

    string s=val["status"].asString();
    if(s.compare("OK")!=0){
        cout<<"注册失败"<<endl;
        return;
    }

    dl_flg=true;
    cout<<"注册成功"<<endl;
    return;
}


void socket_client::user_login(){
    string tel,passwd;
    cout<<"请输入手机号码"<<endl;
    cin>>tel;
    cout<<"请输入密码"<<endl;
    cin>>passwd;

    if(tel.empty()||passwd.empty()){
        cout<<"帐号或密码不能为空"<<endl;
        return;
    }
    Json::Value val;
    val["type"]=DL;
    val["user_tel"]=tel;
    val["user_passwd"]=passwd;

    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"<<endl;
        return;
    }
    val.clear();
    Json::Reader read;
    if(!read.parse(buff,val)){
        cout<<"解析json失败"<<endl;
        return;
    }
    string st=val["status"].asString();
    if(st.compare("OK")!=0){
        cout<<"登陆失败"<<endl;
        return;
    }
    dl_flg=true;

    username=val["user_name"].asString();
    usertel=tel;

    cout<<"登陆成功"<<endl;
    return;

}


void socket_client::user_show_ticket(){
    Json::Value val;
    val["type"]=CKYY;
    send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0);
    char buff[4096]={0};
    int n=recv(sockfd,buff,4095,0);
    //cout<<buff<<endl;
    if(n<=0){
        cout<<"ser close"<<endl;
        return;
    }

    m_val.clear();
    Json::Reader Read;
    if(!Read.parse(buff,m_val)){
        cout<<"json解析失败"<<endl;
        return;
    }

    string st=m_val["status"].asString();
    if(st.compare("OK")!=0){
        cout<<"查询预约信息失败"<<endl;
        return;
    }

    int num=m_val["num"].asInt();
    if(num==0){
        cout<<"没有可预约的信息"<<endl;
        return;
    }

    cout<<"编号  地点名称  总票数 已预订 时间"<<endl; 
    
    for(int i=0;i<num;i++){
        cout<<"-----------------------------------------------"<<endl;
        cout<<"|"<<m_val["arr"][i]["tk_id"].asString()<<"    ";
        cout<<m_val["arr"][i]["add"].asString()<<"    ";
        cout<<m_val["arr"][i]["max"].asString()<<"    ";
        cout<<m_val["arr"][i]["num"].asString()<<"    ";
        cout<<m_val["arr"][i]["use_date"].asString()<<"|"<<endl;
        cout<<"-----------------------------------------------"<<endl;
    }
    cout<<endl;
}



void socket_client::user_subscribe_ticket(){
    user_show_ticket();
    cout<<"请输入要预订的编号:"<<endl;
    int index=0;
    cin>>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"<<endl;
        return;
    }
    val.clear();
    Json::Reader read;
    if(!read.parse(buff,val)){
        cout<<"json 解析失败"<<endl;
        return;
    }
    string st=val["status"].asString();
    if(st.compare("OK")!=0){
        cout<<"预订失败"<<endl;
        return;
    }
    cout<<"预订成功"<<endl;
    return;
}


//取消一个我的预约
void socket_client::user_cancel_sub_ticket(){
    user_show_sub_ticket();
    cout << "请输入要取消的预约ID:" << endl;
    int yd_id = 0;
    cin >> 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"<<endl;
        return;
    }
    val.clear();
    Json::Reader read;
    if(!read.parse(buff,val)){
        cout<<"json 解析失败"<<endl;
        return;
    }
    //待处理失败
    string status = val["status"].asString();
    if (status == "OK") {
        cout << "预约取消成功!" << endl;
    } else {
        // 失败时显示"输入错误"(包含yd_id不存在、无权限等情况)
        cout << "输入错误:该预约ID不存在或您无权取消" << endl;
    }
    return;
    
}


//显示我的预约
void socket_client::user_show_sub_ticket(){
    Json::Value val;
    val["type"] = CKYD;  
    val["tel"] = usertel; 
    
    send(sockfd, val.toStyledString().c_str(), strlen(val.toStyledString().c_str()), 0);

    // 接收服务器响应
    char buff[4096] = {0};
    int n = recv(sockfd, buff, 4095, 0);
    if (n <= 0) {
        cout << "服务器已断开连接" << endl;
        return;
    }

    
    m_val.clear();
    Json::Reader Read;
    if (!Read.parse(buff, m_val)) {
        cout << "json解析失败" << endl;
        return;
    }

    // 检查查询状态
    string st = m_val["status"].asString();
    if (st.compare("OK") != 0) {
        cout << "查询我的预约失败" << endl;
        return;
    }

    // 显示结果
    int num = m_val["num"].asInt();
    if (num == 0) {
        cout << "您暂无预约记录" << endl;
        return;
    }

    cout << "我的预约记录:" << endl;
    cout << "预约ID  项目编号  地点      可使用日期  预约时间" << endl;
    for (int i = 0; i < num; i++) {
        cout << "-------------------------------------------------------------------" << endl;
        cout << "|" << m_val["arr"][i]["yd_id"].asString() << "       ";    // 预约记录ID(sub_ticket.yd_id)
        cout << m_val["arr"][i]["tk_id"].asString() << "    ";         // 项目编号(ticket_info.tk_id)
        cout << m_val["arr"][i]["addr"].asString() << "    ";          // 预约地点(ticket_info.addr)
        cout << m_val["arr"][i]["use_date"].asString() << "    ";      // 可使用日期(ticket_info.use_date)
        cout << m_val["arr"][i]["curr_time"].asString() << "|" << endl;// 预约时间(sub_ticket.curr_time)
        cout << "-------------------------------------------------------------------" << endl;
    }
    cout << endl;
}


void socket_client::run(){
    while(runing){
        print_info();
        switch(user_op){
                case DL:
                user_login();
                break;
                case ZC:
                user_register();
                break;
                case CKYY://查看预约
                user_show_ticket();
                break;
                case YD://预订
                user_subscribe_ticket();
                break;
                case QXYD://取消预订
                user_cancel_sub_ticket();
                break;
                case CKYD://查看预订
                user_show_sub_ticket();
                break;
                case TC://退出
                runing=false;
                break;
            default:
            cout<<"输入无效"<<endl;
            break;
        }
    }
}


int main(){
    socket_client cli;
    if(!cli.connect_server())exit(1);
    cli.run();

    exit(0);
}

可继续优化点:

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

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的跨越嘛~再多做几个玩具就能游龙了吧(应该? 第一阶段的预约系统就到这里啦~

相关推荐
cxr8283 小时前
涌现的架构:集体智能框架构建解析
人工智能·语言模型·架构·1024程序员节·ai智能体·ai赋能
lsx2024063 小时前
jQuery Mobile 实例
开发语言
AI量化投资实验室3 小时前
年化591%,回撤仅7%的策略,支持订阅信号|基于AgentScope开发金融多智能体,附python代码
开发语言·python·金融
兮兮能吃能睡4 小时前
R语言众数函数分析
开发语言·r语言
CaracalTiger4 小时前
告别云端依赖!ComfyUI本地化视频生成实战教程+cpolar实战
python·gpt·开源·aigc·ai编程·1024程序员节·ai-native
心寒丶4 小时前
Linux基础知识(三、Linux常见操作目录命令)
linux·运维·服务器·1024程序员节
ajassi20004 小时前
开源 Linux 服务器与中间件(十二)FRP内网穿透应用
linux·服务器·开源·frp
AAA阿giao4 小时前
JavaScript 中的变量声明:var、let 与 const 深度解析
javascript·笔记
W.Y.B.G4 小时前
css3 学习笔记
笔记·学习·css3·1024程序员节