基于Linux C++ windows QT 开发的在线答题系统

一、项目描述:
 实现功能
          用户的注册、登录,个人答题训练、排位赛(网络匹配对战)、排位系统

1、该项目采用C/S结构基于TCP/IP协议,运用Libevent网络库和线程池进行搭建服务器框架。在传输数据中采用Json进行轻量级的数据格式转换。使用spdlog日志库来记录操作信息、出错信息和提醒消息。

2、使用MySQL数据库来存储注册账号信息,创建一个数据库专门用于存储题库数据

3、单人训练模式:从题库中随机抽取10道题目进行答题,答对继续作答,答错退出答题界面,最后计算的分

4、答题时间设置为10秒,超过答题时间记作答题错误,最终得分与答题时间成正比

5、排位系统:设置用户段位星级登记,只有在上下偏差5颗星的范围内才会匹配成功,如果没有匹配成功,进入到等待队列。有匹配成功的,则将玩家移除等待队列进行答题比赛,答题结束后比较玩家得分情况进行段位改动

二、段位介绍

青铜3  1颗星                到                     星耀1    
   
青铜  3个段位             1--3                 每个段位3颗星        
白银  3个段位             1--3                 每个段位3颗星        
 
黄金  4个段位             1--4                 每个段位4颗星        
铂金  4个段位             1--4                 每个段位4颗星        
 
钻石   5个段位            1--5                 每个段位5颗星        
星耀   5个段位            1--5                 每个段位5颗星        

三、效果展示

四、代码展示

客户端代码(windows下QT开发)

brainstorm.h

#ifndef BRAINSTORM_H
#define BRAINSTORM_H

#include <QDialog>
#include "communicate.h"
#include <QTimer>
namespace Ui {
class BrainStorm;
}

class BrainStorm : public QDialog
{
    Q_OBJECT

public:
    explicit BrainStorm( Communicate *com,QJsonObject &json,QWidget *parent = 0);
    ~BrainStorm();
private:
    void SingelgetQuestion();   //个人训练从服务器获取题目
    void SingelSetQuestion(); //单人训练设置题目
    void SingelAnswerQuestion(int select);//单人训练答题
    void setEnemyScore();//设置对手得分
    void setSelfScore();//设置自己得分
    void setRankQuestion(); //设置排位题目
    void rankAnswerQuestion(int select);//排位回答问题
    void setRankResult(QJsonObject &json);//rank结果
    void showEnquire(QJsonObject &json);
private slots:
    void on_singlepushButton_clicked();

    void on_singl_backButton_clicked();

    void on_single_startButton_clicked();

    void receiveSingelQuestion(QJsonObject json);//单人训练,从服务器接收到题目

    void singelTimerOut();
    void on_singel_selectButton1_clicked();

    void on_singel_selectButton2_clicked();

    void on_singel_selectButton3_clicked();

    void on_singel_selectButton4_clicked();

    void on_backpushButton_clicked();

    void on_rankpushButton_clicked();

    void Rank(QJsonObject json);//接受排位

    void rankTimerOut();



    void on_rankselect1Button_clicked();
    
    void on_rankselect2Button_clicked();
    
    void on_rankselect3Button_clicked();
    
    void on_rankselect4Button_clicked();
    
    void on_backpushButton_2_clicked();

    void on_rankchartpushButton_clicked();

    void on_backpushButton_3_clicked();

private:
    Ui::BrainStorm *ui;
    Communicate *_com; //负责和服务器通信
    QJsonObject _singelQuestion;
    int _currentSingelQuestion;  //当前回答哪一个问题的下标
    QTimer _singelTimer;    //个人训练定时器
    int _singelSec;//个人训练答题时间
    int _singelScore;//个人训练得分

    //rank部分
    QJsonObject _rankQuestion;  //rank的题目
    QString _enemyName;  //对手的名字
    QString _enemyRank;  //对手的段位
    int _enemyScore;     //对手的得分
    int _rankSec;       //rank计时
    int _myScore;       //自己的得分

    QString _userName;  //自己的用户名
    QString _userRank;  //自己的段位
    int _currentRankQuestion;//当前回答问题的下标
    int _enemyRankQuestion;//对手当前问题的下标
    QTimer _rankTimer; //排位赛定时器
};

#endif // BRAINSTORM_H

communicate.h

#ifndef COMMUNICATE_H
#define COMMUNICATE_H

#include <QObject>
#include <QTcpSocket>
#include <QJsonObject>
#include <QJsonDocument>
#include <QHostAddress>
#include "../commom.h"
#include <QJsonArray>
class Communicate : public QObject
{
    Q_OBJECT
public:
    explicit Communicate(QObject *parent = nullptr);

    void writeData(const QJsonObject &json);

signals:
    void rstResult(int );

   void login(QJsonObject json);

   void receiveSingelQuestion(QJsonObject json);

   void Rank(QJsonObject json);

   void Exit(QJsonObject json);
public slots:
    void readData();

private:
    QTcpSocket s;
};

#endif // COMMUNICATE_H

login.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "communicate.h"
#include <QMessageBox>
#include "brainstorm.h"
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();
    void login( QJsonObject json);


private:
    Ui::Widget *ui;

    Communicate *_com;   //通信类指针,负责和服务器通信
};

#endif // WIDGET_H

register.h

#ifndef REGISTER_H
#define REGISTER_H

#include <QDialog>
#include <QJsonObject>
#include "communicate.h"
#include "../commom.h"
#include <QMessageBox>
#include "../commom.h"
namespace Ui {
class Register;
}

class Register : public QDialog
{
    Q_OBJECT

public:
    explicit Register(Communicate *com,QWidget *parent = 0);
    ~Register();

private slots:
    void on_registerpushButton_clicked();

    void on_returnpushButton_clicked();

    void rstResult(int );

private:
    Ui::Register *ui;
    Communicate *_com;
};

#endif // REGISTER_H

brainstorm.cpp

#include "brainstorm.h"
#include "ui_brainstorm.h"

BrainStorm::BrainStorm(Communicate *com,QJsonObject &json,QWidget *parent) :
    QDialog(parent),
    ui(new Ui::BrainStorm)
{
    ui->setupUi(this);
    _com = com;
    _userName = json["userName"].toString();
    _userRank = json["rank"].toString();
    connect(&_singelTimer,SIGNAL(timeout()),this,SLOT(singelTimerOut()));

    connect(_com,SIGNAL(receiveSingelQuestion(QJsonObject)),this,SLOT(receiveSingelQuestion(QJsonObject)));
    connect(_com,SIGNAL(Rank(QJsonObject)),this,SLOT(Rank(QJsonObject)));
    connect(_com,SIGNAL(Exit(QJsonObject)),this,SLOT(Rank(QJsonObject)));


    connect(&_rankTimer,SIGNAL(timeout()),this,SLOT(rankTimerOut()));
}

BrainStorm::~BrainStorm()
{
    delete ui;
}
//个人训练从服务器获取题目
void BrainStorm::SingelgetQuestion()
{
    QJsonObject json;
    json["cmd"] = SINGEL_GETQUESTION;

    _com->writeData(json);
}
//进入个人训练
void BrainStorm::on_singlepushButton_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->singleMenu);
}

void BrainStorm::on_singl_backButton_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->mianMenu);
}
//单人训练设置问题
void BrainStorm::SingelSetQuestion()
{
    ui->singel_questionlabel->setText(_singelQuestion["question"].toArray().at(_currentSingelQuestion).toString());
    ui->singel_selectButton1->setText(_singelQuestion["selection1"].toArray().at(_currentSingelQuestion).toString());
    ui->singel_selectButton2->setText(_singelQuestion["selection2"].toArray().at(_currentSingelQuestion).toString());
    ui->singel_selectButton3->setText(_singelQuestion["selection3"].toArray().at(_currentSingelQuestion).toString());
    ui->singel_selectButton4->setText(_singelQuestion["selection4"].toArray().at(_currentSingelQuestion).toString());

}
//接收题目
void BrainStorm::receiveSingelQuestion(QJsonObject json)
{
    _singelQuestion = json;
    _currentSingelQuestion = 0;
    _singelSec = 10;
    _singelScore = 0;
    ui->lcdNumber->display(_singelSec); //数码管显示时间
    SingelSetQuestion();
    //开启定时器
    _singelTimer.start(1000);
    ui->stackedWidget->setCurrentWidget(ui->singel_running); //跳转到答题页面
}
//开始答题
void BrainStorm::on_single_startButton_clicked()
{
    SingelgetQuestion();
}
//个人训练计时
void BrainStorm::singelTimerOut()
{
    --_singelSec;
    if(_singelSec == 0)
    {
        ui->singel_resultlabel->setText("回答错误");
        QString str = QString("本次得分: %1").arg(_singelScore);
        ui->singel_scorelabel->setText(str);
        _singelTimer.stop();
        ui->stackedWidget->setCurrentWidget(ui->singel_score);
    }
    ui->lcdNumber->display(_singelSec);
}
void BrainStorm::SingelAnswerQuestion(int select)
{
    //回答正确
    if(select == _singelQuestion["answer"].toArray().at(_currentSingelQuestion).toString().toInt())
    {
        _singelScore += 20*_singelSec;
        _currentSingelQuestion++;
        SingelSetQuestion();  //设置下一题
        _singelSec = 10;
        _singelTimer.stop();
        ui->lcdNumber->display(_singelSec);
        _singelTimer.start(1000);
    }
    else //回答错误
    {
        ui->singel_resultlabel->setText("回答错误");
        QString str = QString("本次得分: %1").arg(_singelScore);
        ui->singel_scorelabel->setText(str);
        ui->stackedWidget->setCurrentWidget(ui->singel_score);
        _singelTimer.stop();
    }

    //题目结束
    if(_currentSingelQuestion == QUESTION_NUM)
    {
        ui->singel_resultlabel->setText("恭喜全部答对");
        QString str = QString("本次得分: %1").arg(_singelScore);
        ui->singel_scorelabel->setText(str);
        ui->stackedWidget->setCurrentWidget(ui->singel_score);
        _singelTimer.stop();
    }
}
void BrainStorm::on_singel_selectButton1_clicked()
{
    SingelAnswerQuestion(1);
}

void BrainStorm::on_singel_selectButton2_clicked()
{
    SingelAnswerQuestion(2);
}

void BrainStorm::on_singel_selectButton3_clicked()
{
    SingelAnswerQuestion(3);
}

void BrainStorm::on_singel_selectButton4_clicked()
{
    SingelAnswerQuestion(4);
}

void BrainStorm::on_backpushButton_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->singleMenu);
}



//rank
void BrainStorm::on_rankpushButton_clicked()
{
    QJsonObject json;
    json["cmd"] = RANK;

    _com->writeData(json);

    //跳转到等待页面
    ui->stackedWidget->setCurrentWidget(ui->rank_wait);
}
void BrainStorm::setEnemyScore()
{
    QString str = QString("%1(%2):%3").arg(_enemyName,-5).arg(_enemyRank).arg(_enemyScore);
    ui->enemyStatuslabel->setText(str);
}
void BrainStorm::setSelfScore()
{
    QString str = QString("%1(%2):%3").arg(_userName,-5).arg(_userRank).arg(_myScore);
    ui->selfStatuslabel->setText(str);
}
void BrainStorm::setRankQuestion()
{
   ui->rankQuestion->setText(_rankQuestion["question"].toArray().at(_currentRankQuestion).toString());
   ui->rankselect1Button->setText(_rankQuestion["selection1"].toArray().at(_currentRankQuestion).toString());
   ui->rankselect2Button->setText(_rankQuestion["selection2"].toArray().at(_currentRankQuestion).toString());
   ui->rankselect3Button->setText(_rankQuestion["selection3"].toArray().at(_currentRankQuestion).toString());
   ui->rankselect4Button->setText(_rankQuestion["selection4"].toArray().at(_currentRankQuestion).toString());

   ui->rankselect1Button->setEnabled(true);
   ui->rankselect2Button->setEnabled(true);
   ui->rankselect3Button->setEnabled(true);
   ui->rankselect4Button->setEnabled(true);//设置完题目将四个按钮设置为可使用状态
   ui->rankselect1Button->setStyleSheet("");
   ui->rankselect2Button->setStyleSheet("");
   ui->rankselect3Button->setStyleSheet("");
   ui->rankselect4Button->setStyleSheet("");//设置完题目将按钮清空

   if(_currentRankQuestion == QUESTION_NUM)
   {
        _rankTimer.stop();
        //将结果发送给服务器
        QJsonObject json;
        json["cmd"] = RANKRESULT;
        json["score"] = _myScore;
        json["enemyScore"] = _enemyScore;
        json["enemyName"] = _enemyName;
        _com->writeData(json);

   }

}
void BrainStorm::rankAnswerQuestion(int select)
{
    //答对计算得分
    if(select == _rankQuestion["answer"].toArray().at(_currentRankQuestion).toString().toInt())
    {
         _myScore += 20 * _rankSec;
    }
    setSelfScore();
    _currentRankQuestion++;
    //判断是否跳转到下一题
    if(_currentRankQuestion == _enemyRankQuestion)
    {
        _rankSec = 10;
        _rankTimer.stop();
        ui->lcdNumber_2->display(_rankSec);
        _rankTimer.start(1000);
        setRankQuestion();
    }

    QJsonObject json;
    json["cmd"] = ANSWER;
    json["enemyName"] = _enemyName;
    json["score"] = _myScore;
    json["questionId"] = _currentRankQuestion;
    _com->writeData(json);

}
void BrainStorm::setRankResult(QJsonObject &json)
{
    QString newRank = json["newRank"].toString();
    if(_myScore == _enemyScore)
    {
        ui->rank_resultlabel->setText("平局");
    }
    else if(_myScore > _enemyScore)
    {
        ui->rank_resultlabel->setText("胜利");
    }
    else if(_myScore < _enemyScore)
    {
        ui->rank_resultlabel->setText("失败");
    }

    QString str = QString("%1-------->%2").arg(_userRank).arg(newRank);//段位变化
    ui->newRanklabel->setText(str);
    _userRank = newRank;
    ui->stackedWidget->setCurrentWidget(ui->rank_result);
}
void BrainStorm::showEnquire(QJsonObject &json)
{
    ui->rankchartBrowser->clear();
    qDebug() << "1111111111111111\n";
    QJsonObject json1 = json["order"].toObject();
    auto nameJson = json1["name"].toArray();
    auto rankJson = json1["rank"].toArray();
    int len = json1["name"].toArray().size();
    for(int i = 0;i < len;i++)
    {
        ui->rankchartBrowser->append(nameJson.at(i).toString() + ": " + rankJson.at(i).toString());
    }


}
void BrainStorm::Rank(QJsonObject json)
{
    int cmd = json["cmd"].toInt();
    if(cmd == RANK)
    {
        _rankQuestion = json["question"].toObject();
        _enemyName = json["enemyName"].toString();
        _enemyRank = json["enemyRank"].toString();
        _enemyScore = json["enemyScore"].toInt();
        _enemyRankQuestion = 0;
        _rankSec = 10;
        _myScore = 0;
        ui->lcdNumber_2->display(_rankSec);  //数码管显示时间
        _currentRankQuestion = 0;

        //设置对手的得分
        setEnemyScore();
        setSelfScore();
        setRankQuestion();
        _rankTimer.start(1000);
        ui->stackedWidget->setCurrentWidget(ui->rank_running);
    }
    else if(cmd == ANSWER)
    {
        _enemyScore = json["enemyScore"].toInt();
        _enemyRankQuestion = json["enemyQuestionId"].toInt();
        setEnemyScore();

        if(_currentRankQuestion == _enemyRankQuestion)
        {
            _rankSec = 10;
            _rankTimer.stop();
            ui->lcdNumber_2->display(_rankSec);
            _rankTimer.start(1000);
            setRankQuestion();
        }
    }
    else if(cmd == EXIT)
    {
        _rankTimer.stop();
         QJsonObject json;
        json["cmd"] = RANKRESULT;
        json["enemyscore"] = 0;
        json["score"] = 1;
        _com->writeData(json);

    }
    else if(cmd == RANKRESULT)
   {
       setRankResult(json);
   }
    else if(cmd == ENQUIRE)
    {
        showEnquire(json);
    }
}
void BrainStorm::rankTimerOut()
{
    _rankSec--;
    if(_rankSec == 0)
    {
        if(ui->rankselect1Button->isEnabled())
        {
            _currentRankQuestion++;
        }
        setRankQuestion();
        _rankSec = 10;
    }
    ui->lcdNumber_2->display(_rankSec);
}

void BrainStorm::on_rankselect1Button_clicked()
{
    ui->rankselect1Button->setStyleSheet("background-color: rgb(170, 170, 255)");
    ui->rankselect1Button->setEnabled(false);
    ui->rankselect2Button->setEnabled(false);
    ui->rankselect3Button->setEnabled(false);
    ui->rankselect4Button->setEnabled(false);
    rankAnswerQuestion(1);
}

void BrainStorm::on_rankselect2Button_clicked()
{
    ui->rankselect2Button->setStyleSheet("background-color: rgb(170, 170, 255)");
    ui->rankselect1Button->setEnabled(false);
    ui->rankselect2Button->setEnabled(false);
    ui->rankselect3Button->setEnabled(false);
    ui->rankselect4Button->setEnabled(false);
    rankAnswerQuestion(2);
}

void BrainStorm::on_rankselect3Button_clicked()
{
    ui->rankselect3Button->setStyleSheet("background-color: rgb(170, 170, 255)");
    ui->rankselect1Button->setEnabled(false);
    ui->rankselect2Button->setEnabled(false);
    ui->rankselect3Button->setEnabled(false);
    ui->rankselect4Button->setEnabled(false);
    rankAnswerQuestion(3);
}

void BrainStorm::on_rankselect4Button_clicked()
{
    ui->rankselect4Button->setStyleSheet("background-color: rgb(170, 170, 255)");
    ui->rankselect1Button->setEnabled(false);
    ui->rankselect2Button->setEnabled(false);
    ui->rankselect3Button->setEnabled(false);
    ui->rankselect4Button->setEnabled(false);
    rankAnswerQuestion(4);
}


void BrainStorm::on_backpushButton_2_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->mianMenu);
}

void BrainStorm::on_rankchartpushButton_clicked()
{
    QJsonObject json;
    json["cmd"] = ENQUIRE;
    _com->writeData(json);
    ui->stackedWidget->setCurrentWidget(ui->rankchart);
}

void BrainStorm::on_backpushButton_3_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->mianMenu);
}

communicate.cpp

#include "communicate.h"

Communicate::Communicate(QObject *parent) : QObject(parent)
{
    s.connectToHost(QHostAddress("192.168.1.126"),9999);//连接服务器

    connect(&s,SIGNAL(readyRead()),this,SLOT(readData()));
}

void Communicate::readData()
{
    //读数据
    QByteArray data;
    while(s.bytesAvailable())
    {
        data += s.readAll();
    }

    //数据解析 将读到的数据解析为json字符串
    QJsonDocument dt = QJsonDocument::fromJson(data);
    if(dt.isNull())
    {
        return;
    }

    QJsonObject root = dt.object();

    //具体逻辑处理
    int cmd = root["cmd"].toInt();
    switch (cmd)
    {
    case REGISTER:
        {
        emit rstResult(root["result"].toInt());
        break;
        }
    case LOGIN:
        {
        emit login(root);
        break;
        }
    case SINGEL_GETQUESTION:
        {
        emit receiveSingelQuestion(root["question"].toObject());
        break;
        }
    case RANK:
        {
        emit Rank(root);
        break;
        }
    case ANSWER:
        {
        emit Rank(root);
        break;
        }
    case EXIT:
        {
        emit Exit(root);
        break;
        }
    case RANKRESULT:
        {
        emit Rank(root);
        break;
        }
    case ENQUIRE:
        {
        emit Rank(root);
        break;
        }
    default:
        break;
    }

}

void Communicate::writeData(const QJsonObject &json)
{
    QJsonDocument d(json);
    QByteArray sendData = d.toJson();
    int len = sendData.size();

    //发送数据长度
    s.write((char *)&len,sizeof(int));
    //发送数据本身
    s.write(sendData);
}

login.cpp

#include "login.h"
#include "ui_widget.h"
#include "register.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    _com = new Communicate();
    connect(_com,SIGNAL(login(QJsonObject)),this,SLOT(login(QJsonObject)));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    QString userName = ui->userNamelineEdit->text();
    QString passwd = ui->PasswordlineEdit->text();

    //登陆操作,将登录信息发送给服务器

    QJsonObject json;
    json["cmd"] = LOGIN;
    json["userName"] = userName;
    json["passwd"] = passwd;

    _com->writeData(json); //数据发送给服务器


}

void Widget::on_pushButton_2_clicked()
{
    this->hide();
    Register reg(_com);
    reg.exec();
    this->show();

}
void Widget::login(QJsonObject json)
{
    int result = json["result"].toInt();
    switch (result)
    {
    case OK:
    {
        this->hide();
        BrainStorm *dlg = new BrainStorm(_com,json);
        dlg->show();
        dlg->setAttribute(Qt::WA_DeleteOnClose);
        break;
    }
    case ERROR:
        QMessageBox::critical(this,"登录","登录失败");
        break;
    case NAMEORPASSWD:
        QMessageBox::critical(this,"登录","用户名或密码错误");
        break;
    case USEREXIST:
        QMessageBox::critical(this,"登录","用户已登录,不允许重复登录");
        break;
    default:
        break;
    }
}

register.cpp

#include "register.h"
#include "ui_register.h"

Register::Register(Communicate *com,QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Register)
{
    ui->setupUi(this);
    _com = com;

    connect(_com,SIGNAL(rstResult(int)),this,SLOT(rstResult(int)));
}

Register::~Register()
{
    delete ui;
}

void Register::on_registerpushButton_clicked()
{
    QString userName = ui->userNamelineEdit->text();
    QString passwd = ui->PasswordlineEdit->text();

    //发送注册信息
    QJsonObject json;
    json["cmd"] = REGISTER;
    json["userName"] = userName;
    json["passwd"] = passwd;

    _com->writeData(json); //数据发送给服务器
}
void Register::rstResult(int ret)
{
    switch (ret)
    {
    case OK:
        QMessageBox::information(this,"注册","注册成功");
        break;
    case ERROR:
        QMessageBox::critical(this,"注册","未知错误");
        break;
    case USEREXIST:
        QMessageBox::critical(this,"注册","该用户已存在,注册失败");
        break;
    default:
        break;
    }
}

void Register::on_returnpushButton_clicked()
{
    this->close();
}

main.cpp

#include "login.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

服务器端代码展示(Linux 下QT开发)

 common.h

#ifndef COMMOM_H
#define COMMOM_H
//5XXX  用户操作指令

#define REGISTER             5001  //注册
#define OK                   5000  //注册成功
#define LOGIN                5002  //登录
#define SINGEL_GETQUESTION   5003  //从服务器获取题目
#define RANK                 5004  //进行排位匹配
#define ANSWER               5005  //排位回答一个问题
#define RANKRESULT           5006  //排位结束
#define EXIT                 5007  //排位时一个用户退出
#define ENQUIRE				 5008 //查询排位赛排名
//8XXX 错误
#define ERROR                8001   //位置错误
#define USEREXIST            8002   //用户存在
#define NAMEORPASSWD         8003   //用户名或者密码错误
#define USERLOGIN            8004   //用户已经登录

//其他
#define QUESTION_NUM 5
#endif // COMMOM_H

 database.h

#ifndef DATABASEMENT_H
#define DATABASEMENT_H

#include "mysql/mysql.h"
#include <mutex>
#include "spdlog/spdlog.h"
#include <json/json.h>
#include <string.h>
class DataBasement
{
public:
    DataBasement(const char *host,const char *userName,const char *password,const char *dbName);

    //执行数据库语句
    bool db_exec(const char *sql);


    //数据库查询
    //sql 查询语句  outJson 查询结果
    bool db_select(const char *sql,Json::Value &outJson);
private:
    std::mutex _mutex; //数据库句柄互斥锁
    MYSQL *_mysql;   //数据库句柄

};

#endif // DATABASEMENT_H

 myserver.h

#ifndef MYSERVER_H
#define MYSERVER_H
#include "tcpserver.h"
#include <spdlog/spdlog.h>
#include <databasement.h>
#include <json/json.h>
#include <json/reader.h>
#include "commom.h"
#include <string>
#include <map>
#include "user.h"
#define DEBUG
#define QUESTION_NUM 5
class MyServer:public TcpServer
{
public:
    MyServer();

    void connectEvent(TcpSocket *);
    void readEvent(TcpSocket *);
    void writeEvent(TcpSocket *);
    void closeEvent(TcpSocket *,short);
private:
    void writeData(TcpSocket *s,const Json::Value &inJson);//发送数据
    void Register(TcpSocket *s,const Json::Value &inJson);//用户注册
    void Login(TcpSocket *s,const Json::Value &inJson);//用户登录
    void singelGetQuestion(TcpSocket *s); //个人训练获取题目
    void initRankMap();//初始化rank积分比对表
    void Rank(TcpSocket *s);//进行排位
    void startRank(TcpSocket *first,TcpSocket *second);//开始对战
    void rankAnswerQuestion(TcpSocket *s,Json::Value &inJson);//rank时回答一道问题
    void rankResult(TcpSocket *s, const Json::Value &inJson);
    void Enquire(TcpSocket *s);//获取排位赛排名
private:
    std::shared_ptr<spdlog::logger> _log; //记录日志的句柄
    DataBasement *_db;  //数据库句柄
    //map容器中健是用户名,值是用户指针
    std::mutex _userLock;   //用户列表锁
    std::map<std::string,User *> _users;     //在线用户列表

    //key是rank积分,值是段位说明
    std::map<int,std::string> _rankMap;      //rank积分比对表

    //key为rank积分,value为参与rank的用户socket句柄
    std::mutex _rankLock;
    std::map<int,TcpSocket*> _rankQueue;     //排位匹配等待队列
};

tcpserver.h

#ifndef TCPSERVER_H
#define TCPSERVER_H
#include "thread.h"
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include "tcpsocket.h"
class TcpSocket;
//Tcp服务器的基类
class TcpServer
{
    friend class TcpSocket;
public:
    TcpServer(int threadNum = 8);//开启threadNum个线程
    int listen(int port,const char* ip = nullptr);//监听
    //服务器开始运行
    void start();
protected:
    static void listenCb(struct evconnlistener *,evutil_socket_t,struct sockaddr *,int socklen,void *);//服务器监听回调函数
    //有客户端连接的时候调用这个函数

    //监听处理函数
    void listenEvent(evutil_socket_t fd,struct sockaddr_in *);//listenCb为静态成员函数,访问成员变量不方便,通过该函数来解决


    //-------------------------------虚函数去具体处理客户端的逻辑-------------------------------
    virtual void connectEvent(TcpSocket *){}   //客户端连接事件

    virtual void readEvent(TcpSocket *){}   //客户端可读事件

    virtual void writeEvent(TcpSocket *){}      //客户端可写事件

    virtual void closeEvent(TcpSocket *,short ){}      //客户端关闭事件


private:
    int m_threadNum;//线程个数
    Thread *m_threadPool;//线程池

    struct event_base *m_base;
    struct evconnlistener *m_listener;//监听客户端的连接

    int m_nextThread;//记录下一个线程的下标

};

#endif // TCPSERVER_H

tcpsocket.h

#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include "tcpserver.h"
#include <string>
class TcpServer;
//通信类,负责与客户端的通信

class TcpSocket
{
public:
    TcpSocket(TcpServer *tcpServer,struct bufferevent *bev,char *ip,u_int16_t port);
    //可读事件回调函数
    static void readEventCb(struct bufferevent *bev,void *ctx);  //客户端发送的信息由该函数处理
    //可写事件回调函数
    static void writeEventCb(struct bufferevent *bev,void *ctx); //客户端发送的信息由该函数处理
    //异常事件回调函数
    static void closeEventCb(struct bufferevent *bev,short what,void *stx);

    char *getIp();//获取ip地址

    u_int16_t getPort();//获取端口

    //从客户端读数据
    int readData(void *data,int size);

    //往客户端写数据
    int writeData(const void *data,int size);

    void setUserName(std::string name);
    std::string getUserName();
private:
    static TcpServer *m_tcpServer;   //服务器类对象
    struct bufferevent *m_bev;//用于与客户端通信的句柄
    char *m_ip;               //客户端的ip地址
    u_int16_t m_port;         //客户端端口

    std::string _userName;          //用户名
};

#endif // TCPSOCKET_H

thread.h

#ifndef THREAD_H
#define THREAD_H
#include <stdio.h>
#include <stdlib.h>
#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/event_compat.h>
#include <pthread.h>
#include <unistd.h>
class Thread
{
public:
    Thread();

    void start();//线程运行函数

    struct event_base *getBase(); //获取事件集合
protected:
    static void* worker(void*);//线程工作函数

    void run();//线程的逻辑处理函数,线程工作函数为静态成员变量,想调用成员很麻烦,用该函数来解决
    //静态成员函数只能调用静态成员变量

    static void pipeRead(evutil_socket_t,short,void *);//监听到管道有数据可读的回调函数
private:
    struct event_base *m_base;//开辟base事件池
    pthread_t m_threadId;//线程id

    int m_pipeReadFd;    //管道的读端
    int m_pipeWriteFd;   //管道的写端
    struct event m_pipeEvent;//管道事件
};

#endif // THREAD_H

user.h

#ifndef USER_H
#define USER_H
#include <string>
#include "tcpsocket.h"
class User
{
public:
    User(std::string n,std::string p,int ran,TcpSocket *s);
    TcpSocket *getSocket();

    const char *getName();
    int getRank();
    void setRank(int rank);
private:
    std::string _userName; //用户名
    std::string _passwd;   //用户密码
    int _rank;             //rank分数

    TcpSocket *_s;         //通信套接字类


};

#endif // USER_H

database.cpp

#include "databasement.h"
#include <json/json.h>

DataBasement::DataBasement(const char *host,const char *userName,const char *password,const char *dbName)
{
    //初始化数据库句柄
    _mysql = mysql_init(nullptr);
    if(_mysql == nullptr)
    {
       // spdlog::get("myprojecttxt")->error("数据库初始化失败!");
        exit(-1);
    }

    //连接数据库
    MYSQL *con = mysql_real_connect(_mysql,host,userName,password,dbName,0,nullptr,0);
    if(con == nullptr)
    {
        spdlog::get("myprojecttxt")->error ("连接数据库失败:{}",mysql_error(_mysql));
        exit(-1);
    }
    _mysql = con;

    //设置字符集
    int ret = mysql_query(_mysql,"set names utf8");//设置数据库支持中文
    if(ret != 0)
    {
       spdlog::get("myprojecttxt")->error("数据库设置字符集失败:{}",mysql_error(_mysql));
        exit(-1);
    }
}

bool DataBasement::db_exec(const char *sql)
{
    std::unique_lock<std::mutex> loc{_mutex}; //数据库句柄上锁
    int ret = mysql_query(_mysql,sql);
    if(ret != 0)
    {
        spdlog::get("myprojecttxt")->error("数据库语句执行失败: {}",mysql_error(_mysql));
        return false;
    }

    return true;
}

bool DataBasement::db_select(const char *sql, Json::Value &outJson)
{
     std::unique_lock<std::mutex> lock{_mutex}; //数据库句柄上锁
     int ret = mysql_query(_mysql,sql);
     if(ret != 0)
     {
         spdlog::get("myprojecttxt")->error("数据库语句执行失败: {}",mysql_error(_mysql));
         return false;
     }

     //从mysql服务器下载查询结果
     MYSQL_RES *sql_res = mysql_store_result(_mysql);
     if(sql_res == nullptr)
     {
         if(mysql_errno(_mysql) == 0)
         {
             return true;
         }
         else
         {
             spdlog::get("myprojecttxt")->error("数据库语句执行失败: {}",mysql_error(_mysql));
         }

     }
     MYSQL_ROW row;   //从结果集中一行一行取出数据
     unsigned int num_fileds = mysql_num_fields(sql_res);//获取列数
     MYSQL_FIELD *fetch_field = mysql_fetch_field(sql_res);  //获取表头
     //一行一行获取数据
     while(row = mysql_fetch_row(sql_res))
     {
         for(unsigned int i = 0;i < num_fileds;i++)
         {
             outJson[fetch_field[i].name].append(row[i]);
         }
     }

     mysql_free_result(sql_res);
     return true;
}

myserver.cpp

#include "myserver.h"

MyServer::MyServer()
{
#ifdef DEBUG
    _log = spdlog::stdout_color_mt("console");
#else
    _log = spdlog::rotating_logger_mt("myprojecttxt","myprojecttxt",1024*1024 * 5,3);\
    _log->flush_on(spdlog::level::info);
#endif
    _log->info("1111111111111");

    _db = new DataBasement(nullptr,"xiaowang","xiaowang","BrainStorm");
    initRankMap();

}
void MyServer::connectEvent(TcpSocket *s)
{
    _log->info("有一个新连接[{}:{}]",s->getIp(),s->getPort());
}

void MyServer::readEvent(TcpSocket *s)
{
    char buf[1024] = {0};
    while(1)
    {
        int len = 0;
        s->readData(&len,sizeof(len));
        if(len <= 0)
        {
            break;
        }

        s->readData(buf,len);

        //数据解析,读到的数据为json格式数据
        Json::Value root;
        Json::Reader reader; //json解析器
        if(!reader.parse(buf,root))
        {
            _log->error("数据解析失败");
            return;
        }
        int cmd = root["cmd"].asInt();
        switch (cmd)
        {
        case REGISTER:
            Register(s,root);
            break;
        case LOGIN:
            Login(s,root);
            break;
        case SINGEL_GETQUESTION:
            singelGetQuestion(s);
            break;
        case RANK:
            Rank(s);
            break;
        case ANSWER:
            rankAnswerQuestion(s,root);
            break;
        case RANKRESULT:
            rankResult(s,root);
            break;
        case ENQUIRE:
            Enquire(s);
            break;
        default:
            break;
        }
    }
}

void MyServer::writeEvent(TcpSocket *)
{

}

void MyServer::closeEvent(TcpSocket *s, short)
{
    //用户意外从rank等待队列中退出
    {
        std::unique_lock<std::mutex> lock(_rankLock); //局部锁,要加括号
        int rank = _users[s->getUserName()]->getRank();
        auto it = _rankQueue.find(rank);
        if(it != _rankQueue.end())
        {
            _rankQueue.erase(it);
        }
    }
    //printf("客户端退出,ip: %s  端口: %d\n",s->getIp(),s->getPort());
    std::unique_lock<std::mutex> lock(_userLock);
    std::map<std::string,User *>::iterator it = _users.begin();
    while(it != _users.end())
    {
        if(it->second->getSocket() == s)
        {
            _users.erase(it);
            printf("用户{}{}:{} 退出",it->second->getName(),s->getIp(),s->getPort());

            //释放user
            delete it->second;
            return;
        }
        it++;
    }
    _log->info("{}{} 退出",s->getIp(),s->getPort());
}
void MyServer::writeData(TcpSocket *s, const Json::Value &inJson)
{
    std::string data = inJson.toStyledString();
    s->writeData(data.c_str(),data.length());
}
void MyServer::Register(TcpSocket *s,const Json::Value &inJson)
{
    std::string userName = inJson["userName"].asString();
    std::string passwd = inJson["passwd"].asString();

    //检测用户是否已经注册
    char sql[100] = {0};
    sprintf(sql,"select *from user where name = '%s' and passwd = '%s'",userName.c_str(),passwd.c_str());

    int result = OK;
    Json::Value outJson;
    bool ret = _db->db_select(sql,outJson);
    if(!ret)
    {
        result = ERROR;
        _log->error("查询失败!");
    }
    if(outJson.isMember("name"))  //用户存在,已经注册过了
    {
        result = USEREXIST;
    }
    else
    {
        sprintf(sql,"insert into user(name,passwd,rank) values('%s','%s',0)",userName.c_str(),passwd.c_str());
        bool ret = _db->db_exec(sql);
        if(!ret)
        {
            result = ERROR;
            _log->error("登录失败!");
        }
        else
        {
            _log->info("Register user = {} succeed",userName);
        }
    }
    Json::Value json;
    json["cmd"] = REGISTER;
    json["result"] = result;

    writeData(s,json);

}
void MyServer::Login(TcpSocket *s, const Json::Value &inJson)
{
    int rank = 0;
    std::string userName = inJson["userName"].asString();
    std::string passwd = inJson["passwd"].asString();

    //检测用户是否存在
    char sql[100] = {0};
    sprintf(sql,"select *from user where name = '%s' and passwd = '%s'",userName.c_str(),passwd.c_str());

    int result = OK;
    Json::Value outJson;
    bool ret = _db->db_select(sql,outJson);
    if(!ret)
    {
        result = ERROR;
        _log->error("查询失败!");
    }
    if(outJson.isMember("name"))  //用户已经登录
    {
        std::unique_lock<std::mutex> lock(_userLock);
        if(_users.find(userName) != _users.end())  //用户已经登录
        {
            result = USERLOGIN;
        }
        else
        {
            int i = 0;
            rank = atoi(outJson["rank"][i].asString().c_str());
            User* user = new User(userName,passwd,rank,s);
            _users.insert(make_pair(userName,user));
            _log->info("用户 {}{}:{} 登录成功",userName,s->getIp(),s->getPort());
            s->setUserName(userName);

        }
    }
    else
    {
        result = NAMEORPASSWD;
    }
    Json::Value json;
    json["cmd"] = LOGIN;
    json["result"] = result;
    json["userName"] = userName;
    json["rank"] = _rankMap[rank];

    writeData(s,json);
}
void MyServer::singelGetQuestion(TcpSocket *s)
{
    int result = OK;
    char sql[100] = {0};
    sprintf(sql,"select *from question order by rand() limit %d",QUESTION_NUM);
    Json::Value outJson;
    bool ret = _db->db_select(sql,outJson);
    if(!ret || outJson["question"].size() != QUESTION_NUM)
    {
        result = ERROR;
        _log->error("singelGetQuestion select question error!");
    }

    Json::Value json;
    json["cmd"] = SINGEL_GETQUESTION;
    json["result"] = result;
    json["question"] = outJson;
    _log->info("用户{}[{}:{}] 获取题目:{}\n", s->getUserName(),s->getIp(),s->getPort(),json.toStyledString().c_str());
    writeData(s,json);
}

void MyServer::startRank(TcpSocket *first, TcpSocket *second)
{
    int result = OK;
    char sql[100] = {0};
    sprintf(sql,"select *from question order by rand() limit %d",QUESTION_NUM);
    Json::Value outJson;
    bool ret = _db->db_select(sql,outJson);
    if(!ret || outJson["question"].size() != QUESTION_NUM)
    {
        result = ERROR;
        _log->error("startRank select question error!");
    }

    Json::Value json;
    json["cmd"] = RANK;
    json["result"] = result;
    json["question"] = outJson;
    //first user
    json["enemyName"] = second->getUserName();
    json["enemyRank"] = _rankMap[_users[second->getUserName()]->getRank()];
    json["enemyScore"] = 0;
    writeData(first,json);

    //second user
    json["enemyName"] = first->getUserName();
    json["enemyRank"] = _rankMap[_users[first->getUserName()]->getRank()];
    writeData(second,json);

    _log->info("获取rank题目 :{}\n",json.toStyledString());

}
void MyServer::initRankMap()
{
    char buf[100] = {0};
    int rank = 0;//段位(青铜1/2/3)
    int num = 0; //有多少颗星
    for(int i = 0;i < 100;i++)
    {
        if(i < 9)
        {
            rank = i / 3;
            num = i % 3;
            sprintf(buf,"青铜%d %d颗星",3-rank,num+1);
        }
        else if(9 <= i && i < 18)
        {
            rank = (i - 9) / 3;
            num = (i - 9) % 3;
            sprintf(buf,"白银%d %d颗星",3-rank,num+1);
        }
        else if(18 <= i && i < 34)
        {
            rank = (i - 18) / 4;
            num = (i - 18) % 4;
            sprintf(buf,"黄金%d %d颗星",4-rank,num+1);
        }
        else if(34 <= i && i < 50)
        {
            rank = ( i - 34) / 4;
            num = (i - 34) % 4;
            sprintf(buf,"铂金%d %d颗星",4-rank,num+1);
        }
        else if(50 <= i && i < 75)
        {
            rank = (i - 50) / 5;
            num = (i - 50) % 5;
            sprintf(buf,"钻石%d %d颗星",5-rank,num+1);
        }
        else if(75 <= i && i < 100)
        {
            rank = (i - 75) / 5;
            num = (i - 75) % 5;
            sprintf(buf,"星耀%d %d颗星",5-rank,num+1);
        }
        _rankMap.insert(std::make_pair(i,buf));
    }
   // for(int i = 0;i < 100;i++)
    //{
    //    std::cout << i << ":" << _rankMap[i] << std::endl;
    //}
}
void MyServer::Rank(TcpSocket *s)
{
    TcpSocket *other = nullptr;  //对手
    User *user = _users[s->getUserName()];//获取当前用户名
    int rank = user->getRank();   //获取用户名的rank分

    std::unique_lock<std::mutex> lock(_rankLock);
    //查找同一段位的对手
    std::map<int,TcpSocket*>::iterator it = _rankQueue.find(rank);
    if(it != _rankQueue.end())
    {
        other = it->second;
        _rankQueue.erase(it);
    }
    else  //查找其他段位的选手  积分差值绝对值为小于5的都可以进行对决
    {
        for(int i = 1;i <= 5;i++)
        {
            it = _rankQueue.find(rank + i);
            if(it != _rankQueue.end())
            {
                other = it->second;
                _rankQueue.erase(it);
                break;
            }
            it = _rankQueue.find(rank - i);
            if(it != _rankQueue.end())
            {
                other = it->second;
                _rankQueue.erase(it);
                break;
            }
        }
    }
    _log->info(" rank分数: {}",rank);
    if(other == nullptr)   //没有匹配到对手,将用户加入到等待队列
    {
        _rankQueue.insert(std::make_pair(rank,s));
        _log->info("当前等待 rank人数: {}",_rankQueue.size());
    }
    else  //开始发题
    {
        startRank(s,other);
    }
}
//rank时回答一道问题
void MyServer::rankAnswerQuestion(TcpSocket *s, Json::Value &inJson)
{
    std::string enemyName = inJson["enemyName"].asString();

    User *user = _users[enemyName];
    Json::Value json;
    if(user == nullptr)
    {
        json["cmd"] = EXIT;
        json["enemyScore"] = 0;
        writeData(s,json);
    }
    else
    {
        json["cmd"] = ANSWER;
        json["enemyScore"] = inJson["score"].asInt();
        json["enemyQuestionId"] = inJson["questionId"].asInt();
        writeData(user->getSocket(),json);
    }
}
void MyServer::rankResult(TcpSocket *s, const Json::Value &inJson)
{
    char buf[256] = {0};
    std::unique_lock<std::mutex> lock(_userLock);
    User *user = _users[s->getUserName()];
    int score = inJson["score"].asInt();
    int enemyscore = inJson["enemyScore"].asInt();

    if(score < enemyscore)
    {
        user->setRank(user->getRank() - 1);

    }
    else if(score > enemyscore)
    {
        user->setRank(user->getRank() + 1);
    }
    Json::Value json;
    json["cmd"] = RANKRESULT;
    json["newRank"] = _rankMap[user->getRank()];
    writeData(s,json);
    sprintf(buf,"UPDATE user SET rank = %d WHERE name = '%s'",user->getRank(),s->getUserName().c_str());
    _db->db_exec(buf);

}
void MyServer::Enquire(TcpSocket *s)
{
    Json::Value json;
    Json::Value outJson;
    char buf[1024] = {0};
    sprintf(buf,"SELECT name,rank FROM user ORDER BY rank DESC");
    _db->db_select(buf,outJson);
    json["cmd"] = ENQUIRE;
    json["order"] = outJson;
    writeData(s,json);
}

tcpserver.cpp

#include "tcpserver.h"

TcpServer::TcpServer(int threadNum):m_nextThread(0)
{
    if(threadNum <= 0)
    {
        printf("线程个数不能小于等于0!\n");
        exit(-1);
    }
    //创建线程池
    m_threadNum = threadNum;
    m_threadPool = new Thread[threadNum];
    if(m_threadPool == nullptr)
    {
        printf("线程池创建失败!\n");
        exit(-1);
    }

    m_base = event_base_new();
    if(!m_base)
    {
        printf("监听事件池创建失败\n");
        exit(-1);
    }
}
int TcpServer::listen(int port, const char *ip)
{
    struct sockaddr_in sin;
    memset(&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    if(ip != nullptr)
    {
        inet_aton(ip,&sin.sin_addr);
    }
    m_listener = evconnlistener_new_bind(m_base,listenCb,this,LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,-1,(struct sockaddr *)&sin,sizeof(sin));
    if(!m_listener)
    {
        printf("创建监听失败\n");
        return -1;
    }

    //开启线程池
    for(int i = 0;i < m_threadNum;i++)
    {
        m_threadPool[i].start();
        printf("线程池 %d启动成功\n",i);
    }
    return 0;

}
void TcpServer::listenCb(struct evconnlistener *,evutil_socket_t fd ,struct sockaddr *clientAddr, int, void *data)
{
    TcpServer *p = (TcpServer*)data;
    p->listenEvent(fd,(struct sockaddr_in *)clientAddr);
}
void TcpServer::listenEvent(evutil_socket_t fd, struct sockaddr_in *clientAddr)
{
    char *ip = inet_ntoa(clientAddr->sin_addr); //客户端的ip地址
    uint16_t port = ntohs(clientAddr->sin_port);//客户端端口

    //从线程池中选择一个线程去处理客户端的请求
    //以轮询的方式选择线程
    struct event_base *base = m_threadPool[m_nextThread].getBase();
    m_nextThread = (m_nextThread + 1) % m_threadNum;
    struct bufferevent *bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);//句柄,用于通信
    if(!bev)
    {
        printf("创建套接字失败!\n");
        event_base_loopbreak(base);
        return;
    }
    //创建一个通信对象
    TcpSocket *s = new TcpSocket(this,bev,ip,port);

    //服务器单独封装一个类负责和客户端的通信
    bufferevent_setcb(bev,s->readEventCb,s->writeEventCb,s->closeEventCb,s);
    bufferevent_enable(bev,EV_WRITE);//打开是否可写
    bufferevent_enable(bev,EV_READ);//打开是否可读
    bufferevent_enable(bev,EV_SIGNAL);//
    //bufferevent_disable(bev,EV_READ);
    //bufferevent_write(bev,MESSAGE,strlen(MESSAGE));

    //调用客户端连接事件
    connectEvent(s);
}
void TcpServer::start()
{
    event_base_dispatch(m_base);
    evconnlistener_free(m_listener);
    event_base_free(m_base);
    printf("服务器开启成功,服务器开始运行\n");

}

tcpsocket.cpp

#include "tcpsocket.h"
TcpServer *TcpSocket::m_tcpServer = NULL;
TcpSocket::TcpSocket(TcpServer *tcpServer,struct bufferevent *bev,char *ip,u_int16_t port)
{
    m_tcpServer = tcpServer;
    m_bev = bev;
    m_ip = ip;
    m_port = port;
}
void TcpSocket::readEventCb(bufferevent *, void *ctx)
{
    TcpSocket *s = (TcpSocket*)ctx;
    m_tcpServer->readEvent(s);//通过m_tcpServer指针返回服务器处理
}

void TcpSocket::writeEventCb(bufferevent *, void *ctx)
{
    TcpSocket *s = (TcpSocket*)ctx;
    m_tcpServer->writeEvent(s);//通过m_tcpServer指针返回服务器处理
}

void TcpSocket::closeEventCb(struct bufferevent *,short what,void *ctx)
{
    TcpSocket *s = (TcpSocket*)ctx;
    m_tcpServer->closeEvent(s,what);//通过m_tcpServer指针返回服务器处理
    delete s;
}
char *TcpSocket::getIp()
{
    return m_ip;
}

u_int16_t TcpSocket::getPort()
{
    return m_port;
}

int TcpSocket::readData(void *data, int size)
{
    return bufferevent_read(m_bev,data,size);
}

int TcpSocket::writeData(const void *data, int size)
{
    return bufferevent_write(m_bev,data,size);
}
void TcpSocket::setUserName(std::string name)
{
    _userName = name;
}
std::string TcpSocket::getUserName()
{
    return _userName;
}

thread.cpp

#include "thread.h"

Thread::Thread()
{
    m_base = event_base_new();//初始化base事件池
    if(!m_base)
    {
        printf("创建base事件池失败\n");
        exit(-1);
    }
    //创建管道
    int fd[2];
    if(pipe(fd) == -1)
    {
        perror("pipe");
        exit(-1);
    }

    m_pipeReadFd = fd[0];//pipeEvent监听
    m_pipeWriteFd = fd[1];//主线程收到连接请求写入

    //让管道事件监听管道的读端
    //如果监听到管道的读端有数据可读,通过回调函数写入m_pipeEvent
    event_set(&m_pipeEvent,m_pipeReadFd,EV_READ|EV_PERSIST,pipeRead,this);
    //将事件添加到base集合中
    event_base_set(m_base,&m_pipeEvent);
    //开启事件的监听
    event_add(&m_pipeEvent,0);
}
void Thread::pipeRead(evutil_socket_t,short,void *)
{

}
void Thread::start()
{
    //创建一个线程
    pthread_create(&m_threadId,nullptr,worker,this);
    //线程分离
    pthread_detach(m_threadId);
}
void* Thread::worker(void* arg)
{
    Thread *p = (Thread*)arg;
    p->run();
}
void Thread::run()
{
    //监听base事件池

    event_base_dispatch(m_base);//dispatch死循环,用来处理事件,监听
    event_base_free(m_base);
}
struct event_base *Thread::getBase()
{
    return m_base;
}

user.cpp

#include "user.h"

User::User(std::string n,std::string p,int ran,TcpSocket *s):_userName(n),_passwd(p),_rank(ran),_s(s)
{

}
TcpSocket *User::getSocket()
{
    return _s;
}

const char *User::getName()
{
    return _userName.c_str();
}
int User::getRank()
{
    return _rank;
}
void User::setRank(int rank)
{
    if(rank <= 0)
    {
        rank = 0;
    }
    _rank = rank;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值