Qt视频直播软件--项目实战(Day5)
生活随笔
收集整理的這篇文章主要介紹了
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;//把它轉換成消息發送給serverMyMessage 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_Hwidget.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_OBJECTpublic: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_Htcpthread.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);//等待連接。。。延時三秒,三秒內連不上返回falsem_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
堅持就是勝利!!!!!!
總結
以上是生活随笔為你收集整理的Qt视频直播软件--项目实战(Day5)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 瑞星常识
- 下一篇: 网易云创建添加推荐歌谱和删除操作