Qt-Web混合开发-QWebSocketServer简单服务端(8) 原创

Qt-Web混合开发-使用QWebSocketServer实现的简单服务端程序💚💜🉑🍑

更多精彩内容
👉个人内容分类汇总 👈
👉Qt - Web混合开发👈

1、概述🐛🦆

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

  • WebSocket和Http的异同点

相同:

  1. 建立在TCP之上,通过TCP协议来传输数据;
  2. 都是可靠性传输协议;
  3. 都是应用层协议。

差异:

  1. WebSocket是HTML5中的协议,支持持久连接,HTTP不支持持久连接;
  2. HTTP是单向协议,只能由客户端发起,做不到服务器主动向客户端推送信息。

2、实现效果😅🙏

在这里插入图片描述

3、实现功能🐮🐴

  1. 使用QWebSocketServer创建一个服务端,使用【非安全模式】;
  2. 将所有连接的客户端加入列表,实现服务端同时向所有客户端发送信息;
  3. 实现将客户端传递过来的信息转发给其它所有客户端;
  4. 实现在关闭时释放所有客户端功能。

4、实现流程👊👴👊

  1. 创建QWebSocketServer服务端对象(使用成员指针,没有无参构造);
    • 参数1:表示服务端名称;
    • 参数2:NonSecureMode表示为非安全模式;
  2. 绑定信号槽;
    • newConnection:有新的客户端连接成功信号;
    • closed:服务端关闭监听信号;
  3. 开启服务端监听连接QWebSocketServer::listen(const QHostAddress &*address* = QHostAddress::Any, quint16 *port* = 0);
  4. 当有客户端连接成功后,触发newConnection信号,使用QWebSocket *QWebSocketServer::nextPendingConnection()函数获取连接成功的客户端,然后就和QWebSocket客户端操作流程一样了;
  5. 关闭服务端监听,不再接受新的客户端连接请求,但是已经连接的客户端还可以通信 QWebSocketServer::close()

5、关键代码💳🛣️🍐

  • pro文件
QT += websockets
  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QWebSocketServer>
#include <QtWebSockets>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_newConnection();            // 有新的客户端连接
    void on_closed();                   // 关闭监听成功
    void on_textMessageReceived(const QString &message);     // 有客户端发送信号过来
    void on_disconnected();             // 客户端连接断开
    void on_but_listen_clicked();

    void on_but_send_clicked();

private:
    Ui::Widget *ui;

    QWebSocketServer* m_server = nullptr;
    QList<QWebSocket*> m_clients;
};
#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle(QString("QWebSocketServer服务端简单示例 - V%1").arg(APP_VERSION));  // 设置窗口标题

    m_server = new QWebSocketServer("web服务端", QWebSocketServer::NonSecureMode, this);
    connect(m_server, &QWebSocketServer::newConnection, this, &Widget::on_newConnection);
    connect(m_server, &QWebSocketServer::closed, this, &Widget::on_closed);
}

Widget::~Widget()
{
    // 关闭服务端
    if(m_server->isListening())
    {
        m_server->close();
    }
    // 关闭所有客户端
    qDeleteAll(m_clients.begin(), m_clients.end());

    delete ui;
}

/**
 * @brief 有新的客户端发起连接
 */
void Widget::on_newConnection()
{
    QWebSocket* client = m_server->nextPendingConnection();   // 获取连接成功的客户端

    connect(client, &QWebSocket::textMessageReceived, this, &Widget::on_textMessageReceived);
    connect(client, &QWebSocket::disconnected, this, &Widget::on_disconnected);

    // 将所有客户端加入列表
    m_clients << client;
    ui->textEdit->append(QString("[%1:%2] 连接成功!").arg(client->peerAddress().toString()).arg(client->peerPort()));
}

/**
 * @brief 服务端关闭监听,关闭后不再接收新的客户端的连接请求
 */
void Widget::on_closed()
{
    ui->textEdit->append("服务端关闭监听!");
    ui->but_listen->setText("开启监听");
}

/**
 * @brief 开始监听/关闭服务端监听
 */
void Widget::on_but_listen_clicked()
{
    if(!m_server->isListening())
    {
        bool ret = m_server->listen(QHostAddress::AnyIPv4, 1234);
        if(ret)
        {
            ui->textEdit->append(QString("开始监听:%1").arg(m_server->serverUrl().toString()));
            ui->but_listen->setText("停止监听");
        }
    }
    else
    {
        m_server->close();
    }
}

/**
 * @brief 向所有连接的客户端发送数据
 */
void Widget::on_but_send_clicked()
{
    for(auto client : m_clients)
    {
        client->sendTextMessage(ui->lineEdit_send->text());
    }
}

/**
 * @brief          接收信息并将信息转发给所有客户端
 * @param message
 */
void Widget::on_textMessageReceived(const QString &message)
{
    QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
    for(auto client : m_clients)
    {
        if(client != socket)   // 向所有连接的客户端转发信息,除了当前信息的发出者
        {
            client->sendTextMessage(message);
        }
    }
    ui->textEdit->append(QString("[%1:%2] %3").arg(socket->peerAddress().toString()).arg(socket->peerPort()).arg(message));
}

/**
 * @brief 断开连接时移除对应的客户端
 */
void Widget::on_disconnected()
{
    QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
    for(int i = 0; i < m_clients.count(); ++i)
    {
        if(m_clients.at(i) == socket)
        {
            disconnect(socket, &QWebSocket::textMessageReceived, this, &Widget::on_textMessageReceived);
            disconnect(socket, &QWebSocket::disconnected, this, &Widget::on_disconnected);
            m_clients.removeAt(i);
            break;
        }
    }
    ui->textEdit->append(QString("[%1:%2] 断开连接!").arg(socket->peerAddress().toString()).arg(socket->peerPort()));
}

6、源代码🐍🉐

🐭
╔╝╚══╦══════╦══╗
╠═══╗║╠═══╦╗║╚╗║
║╔═╗║╠═╦═╣║║╚═║║
║╚╗╠╩╗║║╔═╣╚═╦╝║
║║╠╝╔═╩╝║╠╝║╔╝╔╣
║║╚═║╔══╣╔═╝║╚╣║
║╚═╗╚╝║═╝║══╩╚╩╩🧀
╚══╩══╩══╩══════🧀

posted @   mahuifa  阅读(0)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示