Qt视频直播软件--项目实战(Day5)

第五天项目日记

1、今日总结

今天完成客户端第一个界面的编写
客户端的注册、登录 发送账号密码的消息使用json格式

2、设计思路

主要操作数据库,以及一些消息的定义,由于客户端的socket再另一个线程里面,所以接收消息的工作都放在客户端的socket线程,ui的显示由线程发送信号给weidget

3、代码说明

3.1 服务器主要修改代码

在这里插入图片描述

dbhelper.h

新增登录和注册判断
在这里插入图片描述

dbhelper.cpp
QString dbhelper::logic_judge(QString name, QString pswd)
{
    QSqlQuery query(*db);
    query.prepare("select * from user where name = :name");
    //用来绑定值
    query.bindValue(":name",name);

    bool res = query.exec();
    if(!res){
        qDebug()<<query.lastQuery();
    }
    while(query.next()){
        QString _name = query.value("name").toString();
        QString _pswd = query.value("pswd").toString();
        if(_name == name){
            if(pswd == _pswd){
                return "success";
            }else{
                return "pswd_error";
            }
        }
    }

    if(!res){
        //用来打印错误信息
        qDebug()<<query.lastError().text();
    }

    return "no_name";
}

QString dbhelper::user_reg(QString name, QString pswd)
{
    QSqlQuery query(*db);
    //先看一下名字有没有
    query.prepare("select * from user where name = :name");
    query.bindValue(":name",name);
    bool res = query.exec();
    if(!res){
        qDebug()<<query.lastError().text();
        qDebug()<<query.lastQuery();
    }
    qDebug()<<"size = "<<query.size();
    if(query.next()){
        return "rename";//名字重复
    }
    query.prepare("insert into user (name,pswd) values (:name,:pswd)");
    query.bindValue(":name",name);
    query.bindValue(":pswd",pswd);
    res = query.exec();
    if(!res){
        qDebug()<<query.lastQuery();
    }
    return "success";
}
message.h

修改msg的枚举
在这里插入图片描述
增加了函数接口
在这里插入图片描述
在这里插入图片描述

tcpsocket.h

在这里插入图片描述

void TcpSocket::msgPrase(QString msg_buf)
{
    int item;
    QString buf;
    buf.clear();
    item = msg_buf.section('|',0,0).trimmed().toInt();
    int item_len = QString::number(item).length();
    qDebug()<<"len"<<item_len;
    buf = msg_buf.right(msg_buf.length()-item_len-1);
    qDebug()<<"item"<<item<<" "<<buf;
    //把它转换成消息发送给server
    MyMessage message((MsgId)item,buf,buf.length());
    if(message.isInEnum()){
        if(message.getmsgid() == MSG_CLIENT_CLOSE || message.getmsgid() == MSG_CLITEN_CONNECT){
            emit messageToServer(message); //发射消息信号
        }else if(message.getmsgid() == MSG_LOGIC){
            message.setmsgbuf(prase_MSG_LOGIC(message.getmsgbuf()));
            this->write(message.toString().toLatin1(),message.toString().length());
        }else if(message.getmsgid() == MSG_REGISTER){
            message.setmsgbuf(prase_MSG_REG(message.getmsgbuf()));
            this->write(message.toString().toLatin1(),message.toString().length());
        }else if(message.getmsgid() == MSG_SHAKE_HAND){
            message.setmsgbuf(" ");
            this->write(message.toString().toLatin1(),message.toString().length());
        }
    }else{
        qDebug()<<"无效数据";
    }
}

QString TcpSocket::prase_MSG_LOGIC(QString message_buf)
{
    QByteArray bytes = message_buf.toUtf8();
    QJsonParseError jsonError;
    QString name;
    QString pswd;
    QJsonDocument doucment = QJsonDocument::fromJson(bytes, &jsonError);
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
        if (doucment.isObject()){
            QJsonObject object = doucment.object();  // 转化为对象
            if (object.contains("Name")) {
                QJsonValue value = object.value("Name");
                if (value.isString()) {
                    name = value.toString();
                    qDebug() << "Name : " << name;
                }
            }else{
                return "json_error_no_name";
            }
            if (object.contains("password")) {
                QJsonValue value = object.value("password");
                if (value.isString()) {
                    pswd = value.toString();
                    qDebug() << "pswd : " << pswd;
                }
            }else{
                return "json_error_no_pswd";
            }
        }else{
            return "json is no object";
        }
    }else{
        return "json error";
    }
    return mydb->logic_judge(name,pswd);
}

QString TcpSocket::prase_MSG_REG(QString message_buf)
{
    qDebug()<<message_buf;
    QByteArray bytes = message_buf.toUtf8();
    QJsonParseError jsonError;
    QString name;
    QString pswd;
    QJsonDocument doucment = QJsonDocument::fromJson(bytes, &jsonError);
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
        if (doucment.isObject()){
            QJsonObject object = doucment.object();  // 转化为对象
            if (object.contains("Name")) {
                QJsonValue value = object.value("Name");
                if (value.isString()) {
                    name = value.toString();
                    qDebug() << "Name : " << name;
                }
            }else{
                return "json_error_no_name";
            }
            if (object.contains("password")) {
                QJsonValue value = object.value("password");
                if (value.isString()) {
                    pswd = value.toString();
                    qDebug() << "pswd : " << pswd;
                }
            }else{
                return "json_error_no_pswd";
            }
        }else{
            return "json is no object";
        }
    }else{
        return "json error";
    }
    return mydb->user_reg(name,pswd);
}

3.2客户端修改部分

连接的时候根据状态变化发送信号
登录的时候发送登录信号
注册的时候发送注册信号
直接转发收到的字符串
然后在主函数中判断

tcpthread.h
#ifndef TCPTHREAD_H
#define TCPTHREAD_H

#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QDebug>
#include "mymessage.h"

class TcpThread : public QThread
{
    Q_OBJECT
public:
    explicit TcpThread(QObject *parent = 0);
    ~TcpThread();
    void startThread(const QString& ip, int port);
    void stopThread();
    void onSendTcp(QString);
    void parse_msg(QString);

signals:
    void send_tcpmsg(QString);
    void send_logic_msg(QString);
    void send_reg_msg(QString);

public:
    int m_iSendData;
    int m_iRecv_TimeOut;
    int reconnect_num;

private:
    QTcpSocket* m_TcpSocket;
    bool        m_isThreaStopped;
    bool 		m_isOkConect;
    QString 	m_QStrSocketIp;
    int 		m_nSockPort;
    QByteArray 	m_datagram;

protected:
    virtual void run();

private slots:
    void onConnect();
    void onDisConnect();
    void onReadMsg();

public slots:
};

#endif // TCPTHREAD_H

widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMessageBox>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include "tcpthread.h"
#include "mymessage.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    void Logic_Init();//登录初始化
    void User_Init();//使用界面初始化
    void connectToServer(); //用连接服务器

public slots:
    void connect_state(QString); //用来控制连接状态
    void connect_success(); //用来判断连接状态
    void logic_msg_recv(QString); //用来处理登录消息
    void reg_msg_recv(QString); //用来处理注册消息

private slots:
    void on_radioshow_clicked(bool checked); //用来显示密码和隐藏密码

    void on_pushlogic_clicked();//用来登录

    void on_pushquit_clicked();//用来退出

    void on_pushregister_clicked();

signals:
    void connect_enable(); //连接

private:
    Ui::Widget *ui;
    TcpThread *tcpThread;//用来启动socket线程
//    bool status;
    QString userName; //账号
    QString passWord; //密码
    int Logic_Flag; //用来判断是登录还是注册0注册1登录



};

#endif // WIDGET_H

tcpthread.cpp
#include "tcpthread.h"

TcpThread::TcpThread(QObject *parent) :
    QThread(parent)
{
    m_TcpSocket = nullptr ;
    m_isThreaStopped = false;
    m_isOkConect = false;
    reconnect_num = 0;
}

TcpThread::~TcpThread()
{
    m_isThreaStopped = true;
    quit();
    wait();
}

void TcpThread::startThread(const QString &ip, int port)
{
    m_QStrSocketIp = ip;
    m_nSockPort = port;
    m_isThreaStopped = false;
    start();
}

void TcpThread::stopThread()
{
    reconnect_num = 0;
    m_isThreaStopped = true;
}

void TcpThread::run()
{
    bool b_recv_flag = false;
    emit send_tcpmsg("connecting");
    if (!m_TcpSocket)
    {
        m_TcpSocket = new QTcpSocket(this);
        connect(m_TcpSocket, SIGNAL(readyRead()), this, SLOT(onReadMsg()),Qt::DirectConnection);//让接受函数在run子线程中执行(发送者执行)
        connect(m_TcpSocket, SIGNAL(connected()), this, SLOT(onConnect()));
        connect(m_TcpSocket, SIGNAL(disconnected()), this, SLOT(onDisConnect()));
    }
    while (!m_isThreaStopped)
    {
        //检测客户端 socket指针是否为空
        if(b_recv_flag)
            msleep(100);
        if (!m_isOkConect)
        {
            // 终止当前连接并重置套接字(立即关闭套接字,丢弃写缓冲区中的任何挂起数据)
            m_TcpSocket->abort();
            m_TcpSocket->connectToHost(m_QStrSocketIp, m_nSockPort);
            //等待连接。。。延时三秒,三秒内连不上返回false
            m_isOkConect = m_TcpSocket->waitForConnected(3000);
            m_iRecv_TimeOut = -1;
            reconnect_num++;
        }
        if (!m_isOkConect)
        {
            msleep(1);
            if(reconnect_num <3){
                QString reconnect = "reconnect_"+QString::number(reconnect_num);
                emit send_tcpmsg(reconnect);
                continue;
            }else{
                emit send_tcpmsg("overtime");
                break;
            }
        }
        /*else
        {
            qDebug()<<"tcp_flag:"<<m_iRecv_TimeOut;
            QString msg_buf = " ";
            MyMessage msg_shake_hand(MSG_SHAKE_HAND,msg_buf,msg_buf.length());
//            onSendTcp(msg_shake_hand.toString());
            onSendTcp(msg_buf);
        }*/
        b_recv_flag = m_TcpSocket->waitForReadyRead(100);
        if  (b_recv_flag)
        {
            m_iRecv_TimeOut = 0;
        }
        else
        {
            m_iRecv_TimeOut++;
            if(m_iRecv_TimeOut>150) m_iRecv_TimeOut=150;
        }
        if(m_iRecv_TimeOut >= 100){
            QString msg_buf = " ";
            MyMessage msg_shake_hand(MSG_SHAKE_HAND,msg_buf,msg_buf.length());
            onSendTcp(msg_shake_hand.toString());
//            onSendTcp(msg_buf);
        }
        if(m_iRecv_TimeOut >= 150)
        {
            m_iRecv_TimeOut = -1;
        }
    }
    m_TcpSocket->disconnectFromHost();
}

void TcpThread::onConnect()
{
    reconnect_num = 0;
    emit send_tcpmsg("connect");
}

void TcpThread::onDisConnect()
{
    //socket一旦断开则自动进入这个槽函数
    //通过把 m_isOkConect 设为false,在socket线程的run函数中将会重新连接主机
    qDebug()<<"socket is disconnect!"<<endl;
    m_isOkConect = false;
    m_iRecv_TimeOut = -1;
    emit send_tcpmsg("disconnect");
}

void TcpThread::onReadMsg()
{
    if(m_TcpSocket->bytesAvailable() <= 0)
    {
        //  判定连接失败
        m_TcpSocket->disconnectFromHost();
    }
    while (m_TcpSocket->bytesAvailable() > 0)
    {
        // 接收数据
        m_datagram.clear();
        m_datagram.resize(m_TcpSocket->bytesAvailable());
        m_TcpSocket->read(m_datagram.data(), m_datagram.size());
        QString str_tcp_receive = QString::fromLocal8Bit(m_datagram);
        parse_msg(str_tcp_receive);
        qDebug()<<str_tcp_receive;
        msleep(100);
    }
}

void TcpThread::onSendTcp(QString str_info)
{

    if((!m_TcpSocket)||m_TcpSocket->state()!=QAbstractSocket::ConnectedState)
        return;
    m_iSendData = m_TcpSocket->write(str_info.toLatin1(), str_info.length());
    m_TcpSocket->flush();

    if (m_iSendData < 0)
    {
        m_TcpSocket->disconnectFromHost();
        return;
    }
    msleep(1000);
}

void TcpThread::parse_msg(QString msg_buf) //解析接收到的消息
{
    int item;
    QString buf;
    item = msg_buf.section('|',0,0).trimmed().toInt();
    int item_len = QString::number(item).length();
    buf = msg_buf.right(msg_buf.length()-item_len-1);
    if(item == (int)MSG_LOGIC){
        emit send_logic_msg(buf);//发送登录消息
        return;
    }else if(item == (int)MSG_REGISTER){
        emit send_reg_msg(buf);//发送注册消息
        return;
    }
    return;
}

widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QThread>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    tcpThread = nullptr;
    //    status = false;
    Logic_Init();
    QObject::connect(this,SIGNAL(connect_enable()),this,SLOT(connect_success()));
}

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

void Widget::Logic_Init()
{
    this->setWindowTitle("登录/注册");
    ui->linepswd->show();
    ui->lineUser->show();
    ui->radioshow->show();
    ui->pushlogic->show();
    ui->pushregister->show();
    ui->linepswd->setEchoMode(QLineEdit::Password);

    ui->pushAdd->hide();
    ui->pushCreate->hide();
    ui->listView->hide();
    ui->pushquit->hide();
}

void Widget::User_Init()
{
    this->setWindowTitle("云木直播平台");
    ui->linepswd->hide();
    ui->lineUser->hide();
    ui->radioshow->hide();
    ui->pushlogic->hide();
    ui->pushregister->hide();
    ui->label->hide();
    ui->label_2->hide();
    ui->label_3->hide();

    ui->pushAdd->show();
    ui->pushCreate->show();
    ui->listView->show();
    ui->pushquit->show();
}

void Widget::connectToServer()
{
    QString Address_Ip = "127.0.0.1";
    int port = 8010;
    if(!tcpThread){
        tcpThread = new TcpThread;
        QObject::connect(tcpThread,SIGNAL(send_tcpmsg(QString)),this,SLOT(connect_state(QString)));
        QObject::connect(tcpThread,SIGNAL(send_logic_msg(QString)),this,SLOT(logic_msg_recv(QString)));
        QObject::connect(tcpThread,SIGNAL(send_reg_msg(QString)),this,SLOT(reg_msg_recv(QString)));
    }
    tcpThread->startThread(Address_Ip,port);
}

void Widget::connect_state(QString message)
{
    qDebug()<<message;
    if(message == "connecting") {
        ui->label_connect_state->setText("连接中...");
    }else if(message == "connect"){
        ui->label_connect_state->clear();
        emit connect_enable();
        return;
    }else if(message == "disconnect"){
        tcpThread->stopThread();
        return;
    }else if(message == "overtime"){
        QMessageBox::warning(NULL,tr("无法连接"),tr("无法连接请稍后再试"));
        ui->label_connect_state->clear();
        tcpThread->stopThread();
        return;
    }else if(message.left(9) == "reconnect"){
        QString text = "第"+message.right(1)+"次重连中";
        ui->label_connect_state->setText(text);
    }
}

void Widget::connect_success()
{
    QJsonObject json;
    json.insert("Name",userName);
    json.insert("password",passWord);
    QJsonDocument document;
    document.setObject(json);
    QByteArray byteArray = document.toJson(QJsonDocument::Compact);
    QString strJson(byteArray);
    MyMessage mymsg((Logic_Flag?MSG_LOGIC:MSG_REGISTER),strJson,strJson.length());
    qDebug()<<mymsg.toString();
    tcpThread->onSendTcp(mymsg.toString());
}

void Widget::logic_msg_recv(QString message)
{
    if(message == "success"){
        QMessageBox::about(NULL,"登录","登录成功");
        User_Init();
        return;
    }else if(message == "pswd_error"){
        QMessageBox::warning(NULL," 密码错误","密码输入错误请重试");
        tcpThread->stopThread();
        return;
    }
    else if(message == "no_name"){
        QMessageBox::warning(NULL,"未注册","请先注册账号");
        tcpThread->stopThread();
        return;
    }
}

void Widget::reg_msg_recv(QString message)
{
    if(message == "success"){
        QMessageBox::about(NULL,"注册","注册成功");
        tcpThread->stopThread();
        return;
    }else if(message == "rename"){
        QMessageBox::warning(NULL,"用户名重复","请输入其他用户名");
        tcpThread->stopThread();
    }else{
        tcpThread->stopThread();
    }
}


void Widget::on_radioshow_clicked(bool checked)
{
    if(checked){
        ui->linepswd->setEchoMode(QLineEdit::Normal);
    }else{
        ui->linepswd->setEchoMode(QLineEdit::Password);
    }
}

void Widget::on_pushlogic_clicked()
{
    if(ui->lineUser->text().isEmpty()){
        QMessageBox::warning(NULL,tr("输入错误"),tr("账号不能为空"));
        return;
    }
    if(ui->linepswd->text().isEmpty()){
        QMessageBox::warning(NULL,tr("输入错误"),tr("密码不能为空"));
        return;
    }
    userName = ui->lineUser->text();
    passWord = ui->linepswd->text();
    Logic_Flag = 1;
    //连接
    connectToServer();
}

void Widget::on_pushquit_clicked()
{
    tcpThread->stopThread();
    QMessageBox::about(NULL,tr("退出"),tr("点击退出"));
    this->close();
}


void Widget::on_pushregister_clicked()
{
    if(ui->lineUser->text().isEmpty()){
        QMessageBox::warning(NULL,tr("输入错误"),tr("账号不能为空"));
        return;
    }
    if(ui->linepswd->text().isEmpty()){
        QMessageBox::warning(NULL,tr("输入错误"),tr("密码不能为空"));
        return;
    }
    userName = ui->lineUser->text();
    passWord = ui->linepswd->text();
    Logic_Flag = 0;
    //连接
    connectToServer();
}

4、项目文件

源代码文件.

5、效果展示

数据库中的用户如下
在这里插入图片描述
1、测试已有用户是否可以注册
请添加图片描述
2、测试未注册用户是否可以登录
请添加图片描述
3、测试未注册用户能否注册
请添加图片描述
4、测试已有用户密码以及能否登录成功
请添加图片描述
这里服务器用户列表会显示是因为只要建立了连接就会显示,后面会改掉

6、小结

使用了一些QJson

坚持就是胜利!!!!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值