Qt视频直播软件--项目实战(Day1)
一、項目要求
先不寫吧,等寫完了再來補充
二、設計思路
后面補上,今天很晚了,就做一個代碼記錄就好了,都在紙上后面會加進來的
三、第一天項目日記
1、今天總結:
今天編寫了半個服務器,
主要實現的功能
1)能夠使用Tcp協議創建一個服務器,端口自己定義,點擊按鈕開開啟服務器
2)當有服務器連接上來時,能夠顯示連接的用戶,這里為隨機的id號
3)當客戶端斷開時刷新列表,只顯示在線的id,顯示在線客戶端數量
4)客戶端發送數據后消息內容廣播發送所有客戶端
測試:隨便用什么網絡工具都可以,在這里只需要充當客戶端就好了。
2、服務器界面
說明:
開始運行之后,可以輸入端口號,點擊開始服務之后,按鈕變灰,port不能輸入,點擊關閉服務之后退出,在線人數實時顯示在線的客戶端的數量,登錄日志用來查看登錄記錄,暫時不能使用。
有客戶端連接之后顯示連接id,斷開之后實時刷新。
3、代碼結構
說明:tcpsocket 是繼承自QTcpSocket的類
tcpsocket 是繼承自QTcpServer的類
mymessage是自定義的發消息的類
1、mymessage.h
這個沒什么好說的,就是自己封裝一個消息而已
#ifndef MYMESSAGE_H #define MYMESSAGE_H#include <QString>enum MsgId{MSG_CLITEN_CONNECT = 0, //連接消息MSG_READ_BYTES, //讀取接收到的消息MSG_CLIENT_CLOSE, //客戶端關閉的消息 };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(); };#endif // MYMESSAGE_H2、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; }3、tcpsocket.h
繼承自QTcpSocket 然后對部分函數進行了重寫
#ifndef TCPSOCKET_H #define TCPSOCKET_H#include <QWidget> #include <QTcpSocket> #include <QHostAddress> #include "mymessage.h" #include <QDebug>class TcpSocket : public QTcpSocket {Q_OBJECT public:TcpSocket(QObject* parent = 0);signals:void disconnected(int); //發送離線信號void messageToServer(MyMessage); //給server發送消息public slots:void datadisconnected(); //用來處理離線信號void dataReceived(); //用來處理接受到的客戶端的消息 };#endif // TCPSOCKET_H4、tcpsocket.cpp
#include "tcpsocket.h"TcpSocket::TcpSocket(QObject *parent):QTcpSocket(parent) {//本來想要在這里發送連接的信號給服務器的,結果發現在他狀態改變的時候還讀取不到端口號和ip地址,所以就放在房間socket的地方去發送消息了 // connect(this,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(dataconnected()));//連接斷線函數/讀取函數和自定義的槽函數connect(this,SIGNAL(disconnected()),this,SLOT(datadisconnected()));connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived())); }void TcpSocket::datadisconnected() {//斷開之后會發送-1emit disconnected(this->socketDescriptor()); }void TcpSocket::dataReceived() {//處理督導的信號while(this->bytesAvailable() > 0){char buf[1024];int length = bytesAvailable();this->read(buf,length); //讀取接收QString msgbuf = buf;//把它轉換成消息發送給serverMyMessage message(MSG_READ_BYTES,buf,length);emit messageToServer(message); //發射消息信號} }5、tcpserver.h
#ifndef TCPSERVER_H #define TCPSERVER_H#include <QObject> #include <QtNetwork> #include <QTcpServer> #include "tcpsocket.h"class TcpServer : public QTcpServer {Q_OBJECT public:explicit TcpServer(QObject* parent = 0,int port = 0);QList<TcpSocket*> tcpSocketList;//用來存儲客戶端指針的list容器QList<int> descriptorList;//用來對照客戶端的容器,刪除的時候用protected:void incomingConnection(int socketDescriptor);//重寫了連接函數signals:void msgToServer(MyMessage);//用來給main發送消息的信號public slots:void msgFromSocket(MyMessage);//用來處理從socket接收到信號的槽函數void tcpDisconnected(int);//用來處理客戶端斷開的槽函數 };#endif // TCPSERVER_H6、tcpserver.cpp
#include "tcpserver.h"TcpServer::TcpServer(QObject *parent, int port):QTcpServer(parent) {listen(QHostAddress::AnyIPv4,port); //用來監聽ipv4的客戶端,port是傳進來的 }void TcpServer::incomingConnection(int socketDescriptor) {TcpSocket *tcpSocket = new TcpSocket(this);tcpSocket->setSocketDescriptor(socketDescriptor);//發消息給服務器界面QString msgbuf = QString::number(socketDescriptor);//QString msgbuf = tcpSocket->peerAddress().toString()+" "+QString::number(tcpSocket->peerPort());MyMessage message(MSG_CLITEN_CONNECT,msgbuf,msgbuf.length());//qDebug()<<msgbuf << " "<<socketDescriptor;emit msgToServer(message);//發送連接消息connect(tcpSocket, SIGNAL(messageToServer(MyMessage)),this, SLOT(msgFromSocket(MyMessage)));connect(tcpSocket, SIGNAL(disconnected(int)),this, SLOT(tcpDisconnected(int)));//把socket指針放到socketlist中tcpSocketList.append(tcpSocket);//把他的Descriptor放到另一個容器中descriptorList.append(socketDescriptor); }void TcpServer::msgFromSocket(MyMessage message) {emit msgToServer(message);//下面是向客戶端回復相同的數據for(int i = 0; i < tcpSocketList.count(); i++){QTcpSocket *temp = tcpSocketList.at(i);if(temp->write(message.getmsgbuf().toLatin1(), message.getlength()) != message.getlength()){continue;}} }void TcpServer::tcpDisconnected(int descriptor) {//斷開之后 descriptor就會變成-1,所以不知道哪個斷開了,只能自己判斷//所以用一個QList<int>來存儲,到時候哪個變成-1了就說明哪個關掉了for(int i = 0; i < tcpSocketList.count(); i++){QTcpSocket *temp = tcpSocketList.at(i);if(temp->socketDescriptor() == descriptor){temp->destroyed();tcpSocketList.removeAt(i);break;}}int close_descriptor = 0;int j = 0;//對比兩個容器看看哪個客戶端離線了for(int i = 0; i < descriptorList.count(); i++){close_descriptor = descriptorList.value(i);for(j = 0; j < tcpSocketList.count(); j++){QTcpSocket *temp = tcpSocketList.at(j);if(close_descriptor == temp->socketDescriptor()){break;}}if(j == tcpSocketList.count()){//qDebug()<<close_descriptor << "is close";descriptorList.removeAt(i);break;}}//發送該客戶端被關閉的消息QString msgbuf = QString::number(close_descriptor);MyMessage message(MSG_CLIENT_CLOSE,msgbuf,msgbuf.length());emit msgToServer(message);return; }7、mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include "tcpserver.h" #include <QtNetwork> #include <QMessageBox>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void deleteclientlist(int);//用來清除信號客戶端列表private:Ui::MainWindow *ui;QTcpServer *tcpServer;int port;int online_num;public slots:void RecvMsg(MyMessage); private slots:void on_pushclose_clicked();void on_pushopen_clicked(); }; #endif // MAINWINDOW_H8、mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "tcpserver.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);this->setWindowTitle("服務器");ui->lineport->setText("8010");//默認端口號為8010ui->label_onlinenum->setText("0");//默認連接數量肯定是0 }MainWindow::~MainWindow() {delete ui; }void MainWindow::deleteclientlist(int client_id) {int row = 0;QString str = QString::number(client_id);QString line;while(row < ui->listusers->count()){line=ui->listusers->item(row)->text();if(str==line){//qDebug()<<"刪除成功";ui->listusers->takeItem(row);break;}row++;} }void MainWindow::RecvMsg(MyMessage message) {//qDebug()<<message.getmsgbuf().left(message.getlength());if(message.getmsgid() == MSG_CLITEN_CONNECT){ui->listusers->addItem(message.getmsgbuf().left(message.getlength()));ui->label_onlinenum->setText(QString::number(ui->listusers->count()));}else if(message.getmsgid() == MSG_READ_BYTES){//qDebug()<<message.getmsgbuf().left(message.getlength());}else if(message.getmsgid() == MSG_CLIENT_CLOSE){//收到關閉的消息之后刪除那個客戶端的id 消息內容就是客戶端的idthis->deleteclientlist(message.getmsgbuf().toInt());//更新在線人數的labelui->label_onlinenum->setText(QString::number(ui->listusers->count()));}return; }void MainWindow::on_pushclose_clicked() {qApp->quit(); }void MainWindow::on_pushopen_clicked() {if(ui->lineport->text().isEmpty()){QMessageBox::warning(this, tr("warning!!"),tr("please input you Port!"));return;}port = ui->lineport->text().toInt();tcpServer = new TcpServer(this, port);QObject::connect(tcpServer,SIGNAL(msgToServer(MyMessage)),this,SLOT(RecvMsg(MyMessage)));//開啟服務后按鈕不可點擊ui->pushopen->setEnabled(false);ui->lineport->setEnabled(false);return; }4、項目文件
下載地址
5、效果展示
1)能夠使用Tcp協議創建一個服務器,端口自己定義,點擊按鈕開開啟服務器
2)當有服務器連接上來時,能夠顯示連接的用戶,這里為隨機的id號
3)當客戶端斷開時刷新列表,只顯示在線的id,顯示在線客戶端數量
4)客戶端發送數據后消息內容廣播發送所有客戶端
都已經實現了,效果如下
四、記錄結束
結束語:路漫漫其修遠兮,吾將上下而求索!!!
總結
以上是生活随笔為你收集整理的Qt视频直播软件--项目实战(Day1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【密码学】抽象代数——群(学习笔记)
- 下一篇: 印象笔记Mac版的快捷键有哪些?Ever