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_H

2、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_H

4、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()
{
    //断开之后会发送-1
    emit disconnected(this->socketDescriptor());
}

void TcpSocket::dataReceived()
{
    //处理督导的信号
    while(this->bytesAvailable() > 0){
        char buf[1024];
        int length = bytesAvailable();
        this->read(buf,length);         //读取接收
        QString msgbuf = buf;
        //把它转换成消息发送给server
        MyMessage 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_H

6、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_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    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_H

8、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");//默认端口号为8010
    ui->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 消息内容就是客户端的id
        this->deleteclientlist(message.getmsgbuf().toInt());
        //更新在线人数的label
        ui->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)客户端发送数据后消息内容广播发送所有客户端
都已经实现了,效果如下
请添加图片描述

四、记录结束

结束语:路漫漫其修远兮,吾将上下而求索!!!

不多说,本人不大懂C,不能说教程到底怎么样,听说挺好的,为网传资源,资源过大上传乃是下载链接,不多说,下面上目录,行不行您自个儿看着办: 1.01-1-Qt讲解及Qt开发工具(编辑环境)讲解 2.01-2-登录界面布局讲解 3.01-3-登录界面功能介绍讲解: H# E. \' |0 {5 T 4.01-4-手动编写登录界面实现讲解: t# m, S# u7 e" t K. ? 5.01-5-手动编译qt源代码过程讲解 `+ }3 y$ y* r 6.01-6-手动实现信号与槽的连接过程4 M. l0 {# Q6 I& B/ G0 i- M1 L1 c 7.01-7-计算器实现思路讲解 8.02-1- 计算器功能的实现4 M) ?/ t H2 }: W/ I. T2 ^ 9.02-2- 对Qlabel的使用(图片,动画演示) 10.02-3-对apropressbon的使用 11.02-4- 对文本输入框的使用: o5 w4 j8 k( T$ z 12.03-1-多个窗体切换行* D4 u1 C, y- z 13.03-2-QTimer、Qlabel实现倒计时、动画播放+ B; L* k# v5 V6 a( i2 h- N) D 14.03-3-QmessageDialog、QcolorDialog# W+ I4 d4 G: `( I, k$ @4 _ 15.03-4-多个窗体切换(静态公共方法实现16.03-5-QFontDialog、QIapontDialog、Qpropr 17.04-1-QFileDialog、QFile、对文件操作 18.04-2-鼠标事件(单击、双击、移动) 19.04-3-绘图事件9 [' Z2 ^/ t# B" t6 V3 ] 20.04-4-绘图事件例子讲解; J! L7 z. I3 P 21.04-5-关闭事件、窗体大小改变事件) ~# |7 D3 S k' ]% l9 M' \ v 22.05-1-棋盘类背景绘制 23.05-2-棋盘类:画棋盘 24.05-3-棋盘类:画棋盘(2)9 [' z( T+ ]8 w# v 25.05-4-棋盘类:普通落子" U' K1 ~! W6 N; A8 P) J 26.05-5-棋盘:增加位点、增加界面 27.05-6-增加吃子规则 28.05-7-棋盘:实现人人对战 29.05-8-棋盘:实现人机对战( M7 U' T! ~4 b4 @8 q 30.06-1-记事本:界面设计 31.06-2-记事本:新建功能 32.06-3-记事本:打开功能0 `4 Y8 d9 u! `6 ?, e, r 33.06-4-记事本:保存、另存为、退出 34.06-5-编辑、帮助功能. x( I, m, H( k/ y9 S9 g 35.06-6-记事本:右键菜单功能 36.07-1-Qprocess开启新的进程 37.07-2-实现QTimer(用QThread) 38.07-3-窗体附属功能 39.07-4-播放器:界面设计, n: o. O, r2 A# r8 Z1 N1 D 40.07-5-播放器:播放功能, Z) i8 h9 S5 Z5 p! R* ^5 S) a: e 41.07-6-播放器:快进、后退、上一页、下一页、声音调节$ t% z" z y- z! ` 42.07-7-播放器:播放功能的完善7 I/ H* F! j/ e0 }4 f* q) D5 c 43.08-1-播放器:拖动播放0 ?0 u' w8 _3 x/ j) B 44.08-2-播放器:放大、缩小 45.08-3-播放器:键盘放大、缩小 46.08-4-文本框、按钮赋值& Q" x8 J/ G3 a# G/ ?$ B 47.08-5-QListwidpet值切换实现- B* \- l7 L6 Y K8 R 48.08-6-QListwidpet拖动改变值 49.09-1-dow方式对xml读、 50.09-2-dow方式对xml写9 E. Q5 j0 d2 j$ Q: K3 K0 `) Y6 F 51.09-3-stream方式对xml读* D/ S8 S% x; E' s% |. T/ ^ 52.09-4-stream方式对xml写 53.09-5-http请求实现$ Q: ?/ ~1 s- R 54.10-1-http请求获取文件 55.10-2-tcp服务器实现步骤(1) 56.10-3-tcp服务器实现步骤(2) 57.10-4-tcp客户端实现 58.10-5-tcp文件服务器实现 59.11-1- 60.11-2-: {, u9 U) u1 A! B/ B& D7 f 61.11-3-% p& {$ D" J) V# ?. N& `8 u5 o' s2 S" | 62.11-4- 63.12-1-黑白棋:服务器实现) o1 R4 }' k% C" P4 S) g 64.12-2-黑白棋:网络对战实现/ O3 }6 l0 S6 S% J2 |% ^/ [ 65.12-3-SQL对表操作 66.12-4-SQL对表数据操作. q: ]2 K& m9 e$ g S' y 67.12-5-SQL触发器 68.13-1-SQL综合使用(1) 69.13-2-SQL综合使用(2)& R" A5 B# X7 e' |# p+ b 70.13-3-SQL综合使用(3)* V/ M' C) ?: E 71.13-4-SQL综合使用(4) 72.13-5-表设计Qt界面(1) 73.13-6-表设计Qt界面(2) 74.13-7-Qt与SQLite数据库的操作 75.14-1-QTablemodel与SQLite关联. c7 s: Q" K) t+ r! V 76.14-2-SQLite操作:插入 77.14-3-SQLite操作:查询、执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值