• QT聊天室阶段性记录(完善中:注册功能,数据库存储)


    server.h

    #ifndef SERVERDEMO_H
    #define SERVERDEMO_H
    
    #include 
    #include 
    #include 
    #include  //数据库管理类
    #include     //执行sql语句的类
    #include    //数据库记录类
    
    #include "TextMessage.h"
    #include "txtmsgassembler.h"
    #include "TxtMsgHandler.h"
    
    class ServerDemo : public QObject
    {
        Q_OBJECT
    
        QTcpServer m_server;   //服务端类对象
        QMap<QTcpSocket*, TxtMsgAssembler*> m_map;
        TxtMsgHandler* m_handler;
        QSqlDatabase db;
    public:
        ServerDemo(QObject* parent = NULL);
        bool start(int port);   //启动服务端
        void stop();            //停止服务端
        void setHandler(TxtMsgHandler* handler);//设置接口
        ~ServerDemo();
    
    protected slots:
        void onNewConnection(); //新客户端连接槽函数
        void onConnected();     //连接槽函数
        void onDisconnected();  //断连槽函数
        void onDataReady();     //数据接收槽函数
        void onBytesWritten(qint64 bytes);
    };
    
    #endif // SERVERDEMO_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    server.cpp

    #include "ServerDemo.h"
    #include 
    #include 
    #include 
    #include 
    
    ServerDemo::ServerDemo(QObject* parent) : QObject(parent), m_handler(nullptr)
    {
        //判断字节的数据库对象中是否包含了要处理的数据库,如果没有包含则添加一个数据库,否则直接打开
        if( !db.contains("user.db") )
        {
            //添加一个数据库,调用该类中的静态成员函数
            db = QSqlDatabase::addDatabase("QSQLITE");//sqlite3
    
            //设置数据库名字
            db.setDatabaseName("user.db");
        }
    
        //打开数据库
        if( !db.open() )
        {
            qDebug() << "数据库打开失败" << endl;
            return;
        }
    
        //使用sql语句进行表的创建
        QString sql = "create table if not exists user_info("
                      "username varchar(16) primary key,"
                      "password varchar(16),"
                      "status varchar(10),"
                      "level varchar(10))";
        //执行语句
        QSqlQuery querry;
    
        if( !querry.exec(sql) )
        {
            qDebug() << "表创建失败失败" << endl;
            return;
        }
    
        connect(&m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
    }
    
    void ServerDemo::onNewConnection()
    {
        QTcpSocket* tcp = m_server.nextPendingConnection();
        TxtMsgAssembler* assembler = new TxtMsgAssembler();
    
        m_map.insert(tcp, assembler);//用字典容器,为每一个客户端分配一个装配器类对象
    
        connect(tcp, SIGNAL(connected()), this, SLOT(onConnected()));
        connect(tcp, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
        connect(tcp, SIGNAL(readyRead()), this, SLOT(onDataReady()));
        connect(tcp, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
    
        if( m_handler != nullptr )
        {
            TextMessage msg("CONN", tcp->peerAddress().toString() + ":" + QString::number(tcp->peerPort()));
    
            m_handler->handle(*tcp, msg);
        }
    }
    
    void ServerDemo::onConnected()
    {
    
    }
    
    void ServerDemo::onDisconnected()
    {
        QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(sender());
    
        if( tcp != nullptr )
        {
            delete m_map.take(tcp);
    
            if( m_handler != nullptr )
            {
                TextMessage msg("DSCN", "");
    
                m_handler->handle(*tcp, msg);
            }
        }
    }
    
    //循环从缓存区读取数据
    void ServerDemo::onDataReady()
    {
        QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(sender());
        char buf[256] =  {0};
        int len = 0;
    
        if( tcp != NULL )
        {
            //通过字典容器找到发送信息的客户端,
             TxtMsgAssembler* assembler = m_map.value(tcp);
    
            while( (len = tcp->read(buf, sizeof(buf))) > 0 )
            {
                if( assembler != nullptr )
                {
                    QSharedPointer<TextMessage> ptm = nullptr;
    
                    assembler->prepare(buf, len);
    
                    while( (ptm = assembler->assemble()) != nullptr )
                    {
                        if( m_handler != nullptr )
                        {
                            m_handler->handle(*tcp, *ptm);
                        }
                    }
                }
             }
        }
    }
    
    void ServerDemo::onBytesWritten(qint64 bytes)
    {
        (void)bytes;
    }
    
    //开启服务端
    bool ServerDemo::start(int port)
    {
        bool ret = true;
    
        if( !m_server.isListening() )
        {
            ret = m_server.listen(QHostAddress("127.0.0.1"), port);
        }
    
        return ret;
    }
    
    //停止服务端
    void ServerDemo::stop()
    {
        if( m_server.isListening() )
        {
            m_server.close();
        }
    }
    
    //设置接口
    void ServerDemo::setHandler(TxtMsgHandler *handler)
    {
        m_handler = handler;
    }
    
    //服务端析构
    ServerDemo::~ServerDemo()
    {
        const QObjectList& list = m_server.children();
    
        for(int i=0; i<list.length(); i++)
        {
            QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(list[i]);
    
            if( tcp != NULL )
            {
                tcp->close();
            }
        }
    
        const QList<TxtMsgAssembler*>& al = m_map.values();
    
        for(int i = 0; i < al.length(); i++)
        {
            delete al.at(i);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172

    server_main.cpp

    #include 
    #include "serverhandler.h"
    #include "ServerDemo.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        ServerHandler handler;
        ServerDemo server;
    
        server.setHandler(&handler);
        server.start(8888);
    
        return a.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    client.h

    #ifndef CLIENTDEMO_H
    #define CLIENTDEMO_H
    
    #include 
    #include 
    #include "TextMessage.h"
    #include "txtmsgassembler.h"
    #include "TxtMsgHandler.h"
    
    class ClientDemo : public QObject
    {
        Q_OBJECT
    
        QTcpSocket m_client;            //客户端对象
        TxtMsgAssembler m_assembler;    //协议消息装配器
        TxtMsgHandler* m_handler;       //接口函数
    protected slots:
        void onConnected();             //连接事件槽函数
        void onDisconnected();          //断连事件槽函数
        void onDataReady();             //消息事件槽函数
        void onBytesWritten(qint64 bytes);
    
    public:
        ClientDemo(QObject* parent = NULL);
        bool connectTo(QString ip, int port);   //连接服务器
        qint64 send(TextMessage& message);      //发送协议消息
        qint64 available();                     //查看缓冲区数据个数
        void setHandler(TxtMsgHandler* handler);
        bool isValid();                         //判断客户端状态
        void close();                           //关闭客户端
    };
    
    #endif // CLIENTDEMO_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    client.cpp

    #include "ClientDemo.h"
    #include 
    #include 
    
    //信号与槽的映射
    ClientDemo::ClientDemo(QObject* parent) : QObject(parent), m_handler(nullptr)
    {
        connect(&m_client, SIGNAL(connected()), this, SLOT(onConnected()));
        connect(&m_client, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
        connect(&m_client, SIGNAL(readyRead()), this, SLOT(onDataReady()));
        connect(&m_client, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
    }
    
    //连接信号的槽函数
    void ClientDemo::onConnected()
    {
        if( m_handler != nullptr )
        {
            TextMessage conn("CONN", m_client.peerAddress().toString() + ":" + QString::number(m_client.peerPort()));
    
            m_handler->handle(m_client, conn);
        }
    }
    
    //断开连接的槽函数
    void ClientDemo::onDisconnected()
    {
        m_assembler.reset();    //重置装配类对象
    
        if( m_handler != nullptr )
        {
            TextMessage dscn("DSCN", "");
    
            m_handler->handle(m_client, dscn);
        }
    }
    
    //接收数据的槽函数
    void ClientDemo::onDataReady()
    {
        char buf[256] = {0};
        int len = 0;
    
        //循环读取缓冲区中的字节流数据
        while( (len = m_client.read(buf, sizeof(buf))) > 0 )
        {
    
            QSharedPointer<TextMessage> ptm = nullptr;
    
            m_assembler.prepare(buf, len);  //加入存储容器
    
            while( (ptm = m_assembler.assemble()) != nullptr )//循环装配协议文本,直到没有文本可以装配
            {
                if( m_handler != nullptr )
                {
                    m_handler->handle(m_client, *ptm);
                }
            }
        }
    }
    
    void ClientDemo::onBytesWritten(qint64 bytes)
    {
        (void)bytes;
    }
    
    //同步的方式连接服务端
    bool ClientDemo::connectTo(QString ip, int port)
    {
        m_client.connectToHost(ip, port);
        return m_client.waitForConnected();
    }
    
    //以协议消息为单位发送数据
    qint64 ClientDemo::send(TextMessage& message)
    {
        QByteArray ba = message.serialize();
    
        return m_client.write(ba.data(), ba.length());
    }
    
    //查看缓冲区的数据长度
    qint64 ClientDemo::available()
    {
        return m_client.bytesAvailable();
    }
    
    void ClientDemo::setHandler(TxtMsgHandler *handler)
    {
        m_handler = handler;
    }
    
    //查看客户端状态
    bool ClientDemo::isValid()
    {
        return m_client.isValid();
    }
    
    //关闭客户端
    void ClientDemo::close()
    {
        m_client.close();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    client_main.cpp

    #include "MainwinUI.h"
    
    #include 
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWin w;
        w.show();
        return a.exec();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    阶段性效果图

    在这里插入图片描述

  • 相关阅读:
    Java—简单斗地主(集合练习)
    Qt 自定义控件
    接口自动化测试数据驱动DDT模块使用
    34岁本科男,做了5年功能测试想转行,除了进厂还能干什么?
    ubuntu18.4(后改为20.4)部署chatglm2并进行基于 P-Tuning v2 的微调
    AST 初探深浅,代码还能这样玩?
    使用 Hugging Face Transformer 微调 BERT
    Vue笔记(八)Vue3 新特性
    HTML+CSS鲜花静态网页设计
    Linux下C语言使用 netlink sockets与内核模块通信
  • 原文地址:https://blog.csdn.net/m0_72847002/article/details/133619185