Qt-Web混合开发-QWebSocketServer简单服务端(8) 原创
Qt-Web混合开发-使用QWebSocketServer实现的简单服务端程序💚💜🉑🍑
更多精彩内容 |
---|
👉个人内容分类汇总 👈 |
👉Qt - Web混合开发👈 |
1、概述🐛🦆
- Qt版本:V5.12.5
- WebSocket客户端程序
- WebSocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
- WebSocket和Http的异同点
相同:
- 建立在TCP之上,通过TCP协议来传输数据;
- 都是可靠性传输协议;
- 都是应用层协议。
差异:
- WebSocket是HTML5中的协议,支持持久连接,HTTP不支持持久连接;
- HTTP是单向协议,只能由客户端发起,做不到服务器主动向客户端推送信息。
2、实现效果😅🙏
3、实现功能🐮🐴
- 使用QWebSocketServer创建一个服务端,使用【非安全模式】;
- 将所有连接的客户端加入列表,实现服务端同时向所有客户端发送信息;
- 实现将客户端传递过来的信息转发给其它所有客户端;
- 实现在关闭时释放所有客户端功能。
4、实现流程👊👴👊
- 创建QWebSocketServer服务端对象(使用成员指针,没有无参构造);
- 参数1:表示服务端名称;
- 参数2:NonSecureMode表示为非安全模式;
- 绑定信号槽;
- newConnection:有新的客户端连接成功信号;
- closed:服务端关闭监听信号;
- 开启服务端监听连接
QWebSocketServer::listen(const QHostAddress &*address* = QHostAddress::Any, quint16 *port* = 0)
;- 当有客户端连接成功后,触发newConnection信号,使用
QWebSocket *QWebSocketServer::nextPendingConnection()
函数获取连接成功的客户端,然后就和QWebSocket客户端操作流程一样了;- 关闭服务端监听,不再接受新的客户端连接请求,但是已经连接的客户端还可以通信
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、源代码🐍🉐
🐭
╔╝╚══╦══════╦══╗
╠═══╗║╠═══╦╗║╚╗║
║╔═╗║╠═╦═╣║║╚═║║
║╚╗╠╩╗║║╔═╣╚═╦╝║
║║╠╝╔═╩╝║╠╝║╔╝╔╣
║║╚═║╔══╣╔═╝║╚╣║
║╚═╗╚╝║═╝║══╩╚╩╩🧀
╚══╩══╩══╩══════🧀
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构