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

第四天项目日记

1、今日总结

今天开始写客户端
1)先设计登录界面
2)然后用线程开启socket
3)用线程开的话可以实时获取登录的状态
关于TCP我参考了这篇博文

2、设计思路

写的时候试过在连接的时候用信号来处理连接状态,但是发现在等待连接的过程中,ui的控件不会发生改变,说明ui的控件被阻塞了,所以tcp的连接用线程来写,这样就可以实现在界面中实时显示连接状态。

3、代码说明

在这里插入图片描述

widget.ui

在这里插入图片描述
界面如图所示
这里只用了一个界面,然后设计思路是:在登录之前,只显示上面的界面,登录成功之后,只显示下面的界面。
输入用户名密码点击登录,先判断服务器在不在线,如果在线的话就发送用户名密码,然后服务器对客户端发过来的用户名和密码进行判断,如果匹配了就会跳到下面的页面,如果没匹配就返回失败原因

注册的话也是先判断有没有连接上,如果连接上了,就发送注册信息给服务器,如果没连接上就显示连接不到服务器。

两个功能均未完全实现;

tcpthread.h (继承自QThread)

#ifndef TCPTHREAD_H
#define TCPTHREAD_H

#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QDebug>

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

signals:
    void send_tcpmsg(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();
    void onSendTcp(QString);
public slots:
};

#endif // TCPTHREAD_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;
            onSendTcp("");
        }
        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 >= 150)
        {
            m_iRecv_TimeOut = -1;
            m_TcpSocket->disconnectFromHost();
        }
    }

    qDebug()<<"exit_5";

    m_TcpSocket->disconnectFromHost();
    qDebug()<<"exit_6";

}

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);
        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.toStdString().c_str(), strlen(str_info.toStdString().c_str()));
    m_TcpSocket->flush();

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







widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMessageBox>
#include <QDebug>
#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(); //用来表示连接成功

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

    void on_pushlogic_clicked();//用来登录

    void on_pushquit_clicked();//用来退出

private:
    Ui::Widget *ui;
    TcpThread *tcpThread;//用来启动socket线程
//    bool status;
    QString userName; //账号
    QString passWard; //密码

signals:
    void connect_enable(); //连接

};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

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

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)));
    }
    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();
    }else if(message == "disconnect"){
         tcpThread->stopThread();
    }else if(message == "overtime"){
        QMessageBox::warning(NULL,tr("无法连接"),tr("无法连接请稍后再试"));
        ui->label_connect_state->clear();
        tcpThread->stopThread();
    }else if(message.left(9) == "reconnect"){
        QString text = "第"+message.right(1)+"次重连中";
        ui->label_connect_state->setText(text);
    }
}

void Widget::connect_success()
{
    QString msgbuf = userName+" "+ passWard;
    MyMessage mymsg(MSG_LOGIC,msgbuf,msgbuf.length());
    qDebug()<<mymsg.toString();
    tcpThread->send_tcpmsg(mymsg.toString());
    User_Init();
}


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();
    passWard = ui->linepswd->text();
    //连接
    connectToServer();
}

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

mymessage.h

#ifndef MYMESSAGE_H
#define MYMESSAGE_H

#include <QString>

enum MsgId{
    MSG_CLITEN_CONNECT = 0, //连接消息
    MSG_READ_BYTES,   //读取接收到的消息
    MSG_CLIENT_CLOSE,   //客户端关闭的消息
    MSG_LOGIC,  //客户端登录消息
};


class MyMessage
{
    enum MsgId msgid;
    QString msgbuf;
    int length;
public:
    MyMessage();
    MyMessage(MsgId msgid,QString msgbuf,int length);
    void setmsgid(MsgId msgid);
    void setmsgbuf(QString msgbuf);
    void setlength(int length);
    int getmsgid();
    QString getmsgbuf();
    int getlength();
    QString toString();
};

#endif // MYMESSAGE_H

mymessage.cpp

#include "mymessage.h"

MyMessage::MyMessage()
{

}

MyMessage::MyMessage(MsgId msgid, QString msgbuf, int length)
{
    this->msgid = msgid;
    this->msgbuf = msgbuf;
    this->length = length;
}

void MyMessage::setmsgid(MsgId msgid)
{
    this->msgid = msgid;
}

void MyMessage::setmsgbuf(QString msgbuf)
{
    this->msgbuf = msgbuf;
}

void MyMessage::setlength(int length)
{
    this->length = length;
}

int MyMessage::getmsgid()
{
    return msgid;
}

QString MyMessage::getmsgbuf()
{
    return msgbuf;
}

int MyMessage::getlength()
{
    return length;
}

QString MyMessage::toString()
{
    QString send_msg = QString::number(msgid)+"|"+msgbuf;
    return send_msg;
}

4、项目文件

源代码链接接.

5、效果展示

测试如下

1、先测试账号密码不输入的情况下,提示信息
然后测试密码显示和隐藏请添加图片描述
2、测试不开启服务器的情况下登录超时的情况
连接次数三次,每次超时时间为3s,三次结束之后提示连接不到服务器
连接过程中有提示,点击确定之后情况提示
请添加图片描述
3、测试连接过程中开启服务器,自动连接成功(密码验证还没有写)
只测试界面跳转,跳转之后点击退出,客户端退出 退出之后服务器显示的在线列表自动会清掉
请添加图片描述

6、每日总结

今日学会使用 QThread里面创建 QTcpSocket
为了让连接过程中显示连接状态,真的是废了很大的功夫。。。
就这样慢慢成长吧。

另外,要考虑在消息传递的过程中使用 json 格式进行封装一下,所以可能要调研一下 QJson

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT中编译arm-linux-gnueabihf项目需要进行以下几个步骤: 1. 安装交叉编译工具链 在Linux系统中使用以下命令安装交叉编译工具链: ``` sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf ``` 2. 在QT中设置交叉编译工具链 打开QT Creator,在菜单栏中选择“工具”->“选项”->“设备”->“添加”,然后选择“通用 Linux 设备”并点击“下一步”。 在“设备类型”下拉列表中选择“通用 Linux 设备”,在“设备名称”中输入你的设备名称,比如“Raspberry Pi”。 在“SSH”选项卡中输入你的设备IP地址和用户名,并选择“密码”或“密钥”进行身份验证。 在“工具链”选项卡中选择“添加”,然后选择“GCC”并点击“下一步”。 在“工具链名称”中输入你的工具链名称,比如“arm-linux-gnueabihf-gcc”,在“工具链路径”中输入你的交叉编译工具链路径,比如“/usr/bin/arm-linux-gnueabihf-gcc”。 3. 配置QT项目 在QT Creator中打开你的项目,然后在左侧窗口中选择“项目”->“构建设置”->“构建环境”。 在“构建工具”下拉列表中选择“Desktop Qt <版本> <编译器>”,在“设备”下拉列表中选择你的设备名称,比如“Raspberry Pi”。 在“构建步骤”选项卡中选择“自定义步骤”并添加以下命令: ``` make -j4 scp -r <本地路径> <远程路径> ``` 其中“-j4”表示使用4个线程进行编译,“<本地路径>”为你的本地项目路径,“<远程路径>”为你的设备上的路径。 4. 编译和部署项目 在QT Creator中点击“构建”按钮进行编译,然后点击“部署”按钮将项目部署到你的设备上。 注意:在编译和部署过程中可能会出现一些问题,需要根据具体情况进行解决。同时,还需要保证你的设备已经正确连接到网络并且已经安装了必要的库和依赖项。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值