用Qt实现一个桌面弹幕程序(九)-- -- 服务端的实现

本文介绍了如何使用Qt创建一个带界面的弹幕服务端。内容涵盖限制端口号输入范围、开启服务端监听、处理客户端连接、发送JSON数据以及解析JSON。通过Qt的QTcpServer和QDialog构建服务端,并用ClientJob类封装每个客户端连接。
摘要由CSDN通过智能技术生成

又跳票了一段时间,终于有空回归到整题了。。。最近都在学习Ogre所以好久没有更文章了,哈哈。不过杰洛君回来了~

今天要讲的是一个服务端的实现方法~

实现一个带界面的服务端

我们先做一个有界面的服务端版本,然后再讲根据服务器具体的环境制作没有界面的版本~

新建一个项目为TestSrv的项目吧~

注意这里和弹幕程序不同,不需要用QMainWindow作为基类,只需要用QDialog作为基类就可以了~

在设置项目类信息中基类下拉框中选择QDialog吧~

界面的话就直接用拖动控件的方式就好~

控件布局

用到的控件包括一个两个QLabel 三个QPushButton 一个QLineEdit 和一个QListWidget

用布局把它们包好就可以了~

服务端我们这样来处理。因为服务端是服务于多个客户端的,所以每个客户端的工作我们都用一个ClientJob类来包装起来。

新建一个ClientJob.h


#ifndef CLIENTJOBS_H
#define CLIENTJOBS_H

#include <QObject>
#include <QtNetwork>


class ClientJobs : public QObject
{
    Q_OBJECT
public:
    explicit ClientJobs(QObject *parent, QTcpSocket *client, QString strIPPort);        //构造函数
    //TCP连接
    QTcpSocket *m_pClientSock;          //保存客户端的socket连接,达到服务端与客户端长连接
    QString m_strIPPort;//IP_Port       以字符串保存socket连接,用ip_端口号的形式保存
    ~ClientJobs();      //析构函数

signals:
    void CallMainWindowDeleteClient(QString m_strIPPort);       //自定义信号

public slots:
    void SendBytes(QByteArray &data);       //传输二进制字节,弹幕json
    void LostConnection();      //断开连接时的收尾工作
};

#endif // CLIENTJOBS_H

这里我们用到了Socket(套接字) 使用TCP方式进行服务端与客户端之间的传输数据。所以用到了一个QTcpSocket *m_pClientSock;

杰洛君在这里使用了字符串来标识不同的连接,用IP_端口号的形式标识。

在断开连接时用自定义信号来传递要销毁的相应的ClientJob对象。在signals:先得函数声明就是自定义信号了,自定义信号只需要函数声明不需要实现。使用emit 关键字来发送就好。

数据都是用QByteArray的形式进行传输。

这么讲或许还不够清楚~看实现代码就好啦~

#include "clientjobs.h"

ClientJobs::ClientJobs(QObject *parent, QTcpSocket *client, QString strIPPort) :
    QObject(parent)
{
    m_pClientSock = client;
    m_strIPPort = strIPPort;
    //关联信号
    connect(m_pClientSock, SIGNAL(disconnected()), this, SLOT(LostConnection()));
    //可以关联接收数据信号readyRead(),这里不管

}

ClientJobs::~ClientJobs(){
    qDebug()<<"ClientJobs bei xi gou"<<endl;
    m_pClientSock->close();
}

void ClientJobs::SendBytes(QByteArray &data)
{
    m_pClientSock->write(data);     //把弹幕数据通过socket写到客户端
}

void ClientJobs::LostConnection()
{
    //通知主窗口删除自己
    emit CallMainWindowDeleteClient(m_strIPPort);
}

小C:这里信号发送出去后,没有对象响应呀?

杰洛君:诶,真的耶 ,别急嘛~ (~ ̄▽ ̄)→)) ̄▽ ̄)o

这个只是每个链接的一个简易封装。

对这些链接的管理。杰洛君用了DialogSrv类进行管理。这个类才是用到了刚才我们辛苦做的布局,创建我们的主界面~

#ifndef DIALOGSRV_H
#define DIALOGSRV_H

#include <QDialog>
#include <QtNetwork>
#include <QStringList>
#include <QList>
#include <QTimer>
#include <QDateTime>
#include "clientjobs.h"

namespace Ui {
class DialogSrv;
}

class DialogSrv : public QDialog
{
    Q_OBJECT

public:
    explicit DialogSrv(QWidget *parent = 0);        //构造函数
    ~DialogSrv();       //析构函数
    void sendDanmuData(QString ends,QString message);       //发送弹幕

private slots:
    void on_pushButtonListen_clicked();     //按钮函数  这种写法可以不用 connect 来连接信号和槽
    //两个信号的槽函数
    void onNewConnection();     //当有新的连接进来时

    void onTomcatConnection();      //当有网页连接进来时
    //
    void DeleteOneClient(QString strIPAndPort);     //删除一个客户端的长连接

    void on_pushButtonStop_clicked();       //停止按钮被点击时的槽函数

    void on_pushButtonSend_clicked();       //发送测试弹幕按钮的槽函数

    void slotReadTcpData();     //读取Socket传来的弹幕数据

    void sendServerDanmu();     //发送服务端弹幕代码

private:
    Ui::DialogSrv *ui;      //这个程序用到了界面文件
    //server
    QTcpServer *m_pTCPSrv;      //监听客户端Socket

    QTcpServer *t_cTCPSrv;  //监听网页Socket;

    //保存客户列表
    QStringList m_listIPAndPorts;  //IP_Port
    QList<ClientJobs*> m_listClients;//客户端

    QTcpSocket * tcsockclient;      //处理新的Socket连接请求
    QTimer * timer1;        //定时器,在这里可以用来定时发弹幕


};

这个类中有些函数长得比较奇怪,可平时杰洛君命名方式不太一致。

比如:
- void on_pushButtonListen_clicked();
- void on_pushButtonStop_clicked();
- void on_pushButtonSend_clicked();

为什么要这样写函数呢?让我们看会上面杰洛君界面布局的时候3个按钮的名字,有没有发现什么呢?

使得中间的部分就是我们按钮的名字。这种写法&

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值