【QT】Qt中Websocket的使用

news2024/9/22 15:50:29

一、WebSocket的定义

        WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。        

        WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。想对应http协议来说,websocket更加的平等,在http协议中,只有客户端向服务器发送申请请求之后,服务器才会返回请求的数据,如果要保证实时性的话,就需要不断地轮询,每隔一段时间就向服务器发送一个请求,这样就会造成很大的开销,而WebSocket服务器主动向客户端发送数据,而不需要申请,客户端发送数据给服务器也是如此

        简单来说,就是浏览器和服务器之间通信的一种协议,相比较http来说,数据交换更加平等,开销更小;

二、服务器和客户端

        要想在Qt实现websocket那么我们主要的就是实现一个服务器,由网页实现一个客户端

2.1 服务器的实现

        要实现服务器,首先要认识QWebSocketServer Class,我们需要通过这个类实现

 1)类分析

        从上图可以知道,需要在.pro文件中添加QT+=websockets,然后添加头文件,新建一个WebSocketTest窗口应用程序,试图如下

2)添加库

        在WebSocketTest中添加下面的语句

QT       += websockets

3)添加头文件

        在websockettest.h中添加头文件,声明变量

#ifndef WEBSOCKETTEST_H
#define WEBSOCKETTEST_H

#include <QWidget>
#include <QWebSocketServer>

QT_BEGIN_NAMESPACE
namespace Ui { class WebSocketTest; }
QT_END_NAMESPACE

class WebSocketTest : public QWidget
{
    Q_OBJECT

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

private:
    Ui::WebSocketTest *ui;

    //声明QWebSocketServer变量
    QWebSocketServer *web_server;

};
#endif // WEBSOCKETTEST_H

4)QWebSocketServer类的使用

        再来看一看关于这个类的使用,类名上面F1进入帮助界面,可以看到

翻译过来就是

QWebSocketServer是一个基于QTcpServer模型的类,用于处理WebSocket协议的服务器端通信。如果你知道如何使用QTcpServer,你就可以很轻松的使用QWebSocketServer。

QWebSocketServer类主要用于接收并处理来自客户端的WebSocket连接,你可以手动设定服务端的端口,也可以让QWebSocketServer自动选择。调用listen()函数即可让服务器开始侦听连接请求。

每当有新的客户端尝试连接服务器时,newConnection()信号就会发出。服务器可以调用nextPendingConnection()方法接受这个握手请求,同时返回一个已经连接状态的QWebSocket对象指针,服务器即可通过这个指针和客户端进行通信。

如果在过程中发生错误,serverError()方法可以获取错误类型,同时可以调用errorString()方法获取人类可读的错误描述。

当服务器侦听连接请求时,可以通过serverAddress()和serverPort()来获取服务器正在侦听的地址和端口。调用close()函数可以使QWebSocketServer停止侦听连接请求。

QWebSocketServer当前还不支持WebSocket拓展和WebSocket子协议。该类仅支持RFC 6455中规定的WebSocket协议的13版。

有一个默认的握手超时设置为10秒,主要用于防止拒绝服务攻击,该超时时间可以通过setHandshakeTimeout()自定义。

参见WebSocket Server Example和QWebSocket。

        也就是说使用listen函数监听连接请求,一旦有新的客户端连接,就可以触发newConnection()信号,再由服务器通过nextPendingConnection()方法接收这个客户端的连接,这个方法返回一个QWebsocket的对象指针,通过这个指针就可以和客户端通信了

5)代码实现

        首先客户端代码我这里直接提供一个可以测试的html,新建一个文本文件,将下面内容复制进去,保存后,将后缀改为html,点击使用浏览器打开。

<!DOCTYPE html>
<html>
<head>
<title>WebSocket Test</title>
<style>
    #testButton {
        display: block;
        margin: 20px auto;
        padding: 10px 20px;
        font-size: 16px;
    }
    #messageDisplay {
        margin: 20px auto;
        padding: 10px;
        border: 1px solid #ccc;
        width: 80%;
        height: 200px;
        overflow-y: scroll;
        font-size: 14px;
    }
</style>
</head>
<body>
<button id="testButton">Send Test Message</button>
<div id="messageDisplay"></div>

<script>
var ws = new WebSocket('ws://localhost:15678');

ws.onopen = function() {
    console.log('WebSocket connection opened.');
};

ws.onmessage = function(event) {
    console.log('Message from server:', event.data);
    var messageDisplay = document.getElementById('messageDisplay');
    messageDisplay.innerHTML += '<p>' + event.data + '</p>';
};

ws.onerror = function(error) {
    console.error('WebSocket error:', error);
};

ws.onclose = function() {
    console.log('WebSocket connection closed.');
};

document.getElementById('testButton').onclick = function() {
    ws.send('Test');
    console.log('Test message sent.');
};
</script>
</body>
</html>

服务器相关代码

构造函数

 web_server = new QWebSocketServer("Myserver",QWebSocketServer::NonSecureMode,this);

    if(web_server->listen(QHostAddress::Any,15678))
    {
        qDebug()<<"开始监听";
        connect(web_server,&QWebSocketServer::newConnection,this,&WebSocketTest::newCilentConnect);

    }

槽函数

void WebSocketTest::newCilentConnect()
{
    //返回客户端
    web_client = web_server->nextPendingConnection();
    qDebug() << "有新的 WebSocket 客户端连接。";

}

编译运行服务器,然后点击html文件,可以发现会打印”有新的 WebSocket 客户端连接“;

6)接收客户端的消息

void WebSocketTest::newCilentConnect()
{
    //返回客户端
    web_client = web_server->nextPendingConnection();
    qDebug() << "有新的 WebSocket 客户端连接。";

    // 处理接收到的消息
    connect(web_client , &QWebSocket::textMessageReceived, this, &WebSocketTest::onTextMessageReceived);

}

void WebSocketTest::onTextMessageReceived(const QString &message)
{
      qDebug() << "收到客户端消息:" << message;

      if(message=="Test")
      {
           /*在这里执行你实现的操作,如网页一个按钮,点击后发送打开摄像头信息给服务器,
           服务器执行打开摄像头的操作*/
       }
}

        编译运行,点击网页上的按钮,服务器就可以收到这个消息了;

2.2 客户端的实现

        到前面为止就可以实现客户端发送数据到服务器的操作,现在实现服务器发送数据给客户端


// 向客户端发送数据
void WebSocketTest::sendClientData(const QString &str)
{
    if (web_client->isValid()) {
        web_client->sendTextMessage(str);
    }
}

然后在界面上添加一个按钮发送信息给客户端


void WebSocketTest::on_btn_send_clicked()
{
    sendClientData("Hello");
}

编译运行,刷新网页后,点击按钮查看效果

 三、完整源码

websocket.c

#include "websockettest.h"
#include "ui_websockettest.h"

WebSocketTest::WebSocketTest(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::WebSocketTest)
{
    ui->setupUi(this);

    // 创建 WebSocket 服务器
    web_server = new QWebSocketServer("Myserver",QWebSocketServer::NonSecureMode,this);

    //监听
    if(web_server->listen(QHostAddress::Any,15678))
    {
        qDebug()<<"开始监听";
        connect(web_server,&QWebSocketServer::newConnection,this,&WebSocketTest::newCilentConnect);

    }


}

void WebSocketTest::newCilentConnect()
{
    web_client = web_server->nextPendingConnection();
    qDebug() << "有新的 WebSocket 客户端连接。";


    // 处理客户端断开连接
    connect(web_client, &QWebSocket::disconnected, this, [this, web_client]() {
        qDebug() << "WebSocket 客户端断开连接。";
        web_client->deleteLater();
    });
    // 处理接收到的消息
    connect(web_client, &QWebSocket::textMessageReceived, this, &WebSocketTest::onTextMessageReceived);

}
void WebSocketTest::onTextMessageReceived(const QString &message)
{
      qDebug() << "收到客户端消息:" << message;


}

// 向客户端发送数据
void WebSocketTest::sendClientData(const QString &str)
{
    if (web_client->isValid()) {
        web_client->sendTextMessage(str);
    }
}

void WebSocketTest::on_btn_send_clicked()
{
    sendClientData("Hello");
}

WebSocketTest::~WebSocketTest()
{
    delete ui;
}



websocket.h

#ifndef WEBSOCKETTEST_H
#define WEBSOCKETTEST_H

#include <QWidget>
#include <QWebSocketServer>
#include <QDebug>
#include <QWebSocket>


QT_BEGIN_NAMESPACE
namespace Ui { class WebSocketTest; }
QT_END_NAMESPACE

class WebSocketTest : public QWidget
{
    Q_OBJECT

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

private:
    Ui::WebSocketTest *ui;

    //声明QWebSocketServer变量  服务器
    QWebSocketServer *web_server;

    //客户端
    QWebSocket* web_client;

private slots:
    //客户端连接槽函数
    void newCilentConnect();
    
    //接收新客户端消息函数
    void onTextMessageReceived(const QString &message);

    //发送消息给客户端函数
    void on_btn_send_clicked();

private:
    //发送消息给客户端
    void sendClientData(const QString &str);

};
#endif // WEBSOCKETTEST_H

websocket.html

<!DOCTYPE html>
<html>
<head>
<title>WebSocket Test</title>
<style>
    #testButton {
        display: block;
        margin: 20px auto;
        padding: 10px 20px;
        font-size: 16px;
    }
    #messageDisplay {
        margin: 20px auto;
        padding: 10px;
        border: 1px solid #ccc;
        width: 80%;
        height: 200px;
        overflow-y: scroll;
        font-size: 14px;
    }
</style>
</head>
<body>
<button id="testButton">Send Test Message</button>
<div id="messageDisplay"></div>

<script>
var ws = new WebSocket('ws://localhost:15678');

ws.onopen = function() {
    console.log('WebSocket connection opened.');
};

ws.onmessage = function(event) {
    console.log('Message from server:', event.data);
    var messageDisplay = document.getElementById('messageDisplay');
    messageDisplay.innerHTML += '<p>' + event.data + '</p>';
};

ws.onerror = function(error) {
    console.error('WebSocket error:', error);
};

ws.onclose = function() {
    console.log('WebSocket connection closed.');
};

document.getElementById('testButton').onclick = function() {
    ws.send('Test');
    console.log('Test message sent.');
};
</script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1990181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HelloWorld驱动编写和加载驱动实验

HelloWorld驱动编写和加载驱动实验 Helloworld驱动实验驱动编写驱动的基本框架 内核模块实验设置交叉编译器找到RK3568平台交叉编译器&#xff1a;解压交叉编译器&#xff1a;设置全局的交叉编译器环境验证交叉编译器环境 编写Makefile编译模块模块的加载与卸载查看模块信息 He…

WT2605C蓝牙语音芯片赋能对讲机新体验:无屏操控、音频解码与蓝牙音箱三合一

一、产品概况 对讲机市场是一个技术成熟且具有广泛应用前景的市场。对讲机作为无线通信设备的一种&#xff0c;在许多不同的领域和业务中发挥着重要作用。从技术发展角度来看&#xff0c;对讲机经历了从模拟到数字的转型&#xff0c;以及从简单通信工具向多功能设备的演进。当…

LVS实验——部署DR模式集群

目录 一、实验环境 二、配置 1、LVS 2、router 3、client 4、RS 三、配置策略 四、测试 1.Director服务器采用双IP桥接网络&#xff0c;一个是VPP&#xff0c;一个DIP 2.Web服务器采用和DIP相同的网段和Director连接 3.每个Web服务器配置VIP 4.每个web服务器可以出外网…

【Python机器学习】回归——缩减系数来“理解”数据

如果数据特征比样本点还多&#xff0c;是不可以使用线性回归的&#xff0c;因为在计算的时候会出错。 如果特征比样本点还多&#xff08;n>m&#xff09;&#xff0c;也就是说输入数据的矩阵x不是满秩矩阵。非满秩矩阵在求逆时会出问题。 为了解决上述问题&#xff0c;可以…

贪心算法的初涉(双指针 + “过山车思想”)

“过山车”思想 首先我们用一道力扣的题目&#xff0c;来简单了解一下“过山车思想” 3228. 将 1 移动到末尾的最大操作次数 - 力扣&#xff08;LeetCode&#xff09; 给你一个 二进制字符串 s。 你可以对这个字符串执行 任意次 下述操作&#xff1a; 选择字符串中的任一…

京东京造的C2M供应链模式

京东自有品牌业务于2018年1月正式上线&#xff0c;在京东发展已久&#xff0c;依托京东供应链优势&#xff0c;已搭建出京东京造、惠寻、佳佰等多品牌矩阵。 京东给零售企业释放出了一个讯号&#xff1a;C2M崛起&#xff0c;消费者的需求开始走向多元化和个性化&#xff01; …

徐州市委书记宋乐伟一行莅临非凸科技徐州分公司调研

7月23日&#xff0c;徐州市委书记宋乐伟一行莅临非凸科技徐州分公司调研&#xff0c;详细了解非凸科技数智交易产品的生态体系以及AI算力赋能的实践成果&#xff0c;并就相关工作进行了现场指导与交流。 非凸科技徐州分公司位于淮海路经济区金融服务中心云盛大厦&#xff0c;致…

基于JSP、java、Tomcat三者的项目实战--校园交易平台系统--(实习,答辩皆可用到)--万字爆更

技术支持&#xff1a;JAVA、JSP 服务器&#xff1a;TOMCAT 7.0.86 编程软件&#xff1a;IntelliJ IDEA 2021.1.3 x64 全部文件展示 网页实现功能截图 主页 注册 登录 购物车主页 修改功能 修改成功 添加商品功能 添加成功 添加进入购物车功能 支付功能 支付过的历史清单账单…

Comsol 声固耦合条件下超长水管路声传递损失

声固耦合条件指的是声波在固体和液体之间传递时&#xff0c;两者之间存在接触或耦合的情况。在水管路中&#xff0c;声固耦合条件下的声传递损失可以通过以下几个因素来影响和计算&#xff1a; 1. 声波的反射和透射&#xff1a;当声波从一个介质传递到另一个介质时&#xff0c…

服务器 Linux 的网络信息

博主上回大致讲解了文件系统&#xff0c;今天来说说 Linux 的网络信息&#xff0c;还是比较重要的~ 主机名称 临时修改 hostname node01 永久修改 vi /etc/hostname DNS解析 域名解析服务可以将域名转换为IP地址DNS域名劫持 window --> C:\Windows\System32\drivers…

Java 2.2 - Java 集合

Java 集合&#xff0c;也叫做容器&#xff0c;主要是由两大接口派生而来&#xff1a;一个是 Collection 接口&#xff0c;主要用于存放单一元素&#xff1b;另一个是 Map 接口&#xff0c;主要用于存放键值对。对于 Collection 接口&#xff0c;其下又有三个主要的子接口&#…

七大云安全威胁及其应对方法

关注公众号网络研究观获取更多内容。 对于任何依赖云来容纳快速增长的服务的企业来说&#xff0c;确保安全都是重中之重。然而&#xff0c;正如大多数云采用者很快意识到的那样&#xff0c;迁移到动态云环境需要新的和更新的安全措施&#xff0c;以确保数据和其他关键资产在整…

凯特王妃与戴安娜王妃:有跨越时空的优雅共鸣!

显而易见的是都是王妃,而王妃不仅是称谓也是一个头衔,她们同时要承担这个头衔应尽的职责! 在皇室世界里,总有一些名字,如同璀璨星辰,即便时光流转,依旧熠熠生辉。现在让我们揭开一段不为人知的幕后故事——凯特王妃与已故的戴安娜王妃之间,那些超越时代、共通的优雅与情…

前端模块化-手写mini-vite

前言 本文总结了一些关于 Vite 的工作原理&#xff0c;以及一些实现细节。 本节对应的 demo 可以在这里找到。 什么是 Vite Vite 是一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports&#xff0c;在服务器端按需编译返回&#xff0c;完全跳过了打包这个…

PyTorch深度学习实战(5)—— Tensor的命名张量和基本结构

1. 命名张量 命名张量&#xff08;Named Tensors&#xff09;允许用户将显式名称与Tensor的维度关联起来&#xff0c;便于对Tensor进行其他操作。笔者推荐使用维度的名称进行维度操作&#xff0c;这样可以避免重复计算Tensor每个维度的位置。支持命名张量的工厂函数&#xff08…

怎么删除iPhone重复照片:解放你的存储空间

在数字化时代&#xff0c;iPhone已成为我们记录生活点滴的重要工具。从家庭聚会的快乐时光到户外冒险的壮观景象&#xff0c;我们依靠iPhone捕捉无数珍贵瞬间。然而&#xff0c;这种便利性带来的一个副作用是&#xff0c;相册很快就会充满重复的照片&#xff0c;不仅占用了宝贵…

【IC设计】时序分析面试题总结(亚稳态、建立/保持裕量计算、最高时钟频率计算、时序违例解决办法)

文章目录 基本概念亚稳态建立时间和保持时间 常见问题1.为什么触发器要满足建立时间和保持时间&#xff1f;2.建立时间裕量和保持时间裕量的计算&#xff1f;3.最高时钟频率的计算&#xff1f;流水线思想&#xff1f;4.时序违例的解决办法&#xff1f; 基本概念 亚稳态 亚稳态…

简单的 CompletableFuture学习笔记

简单的 CompletableFuture学习笔记 这里记录一下自己学习的内容&#xff0c;简单记录一下方便后续学习&#xff0c;内容部分参考 CompletableFuture学习博客 1. CompletableFuture简介 在api接口调用时间过长&#xff0c;调用过多外围接口时&#xff0c;为了提升性能&#x…

Self-study Python Fish-C Note14 P50to51

函数 (part 4) 本节主要讲函数 递归 递归 (recursion) 递归就是函数调用自身的过程 示例1&#xff1a; def fun1(i):if i > 0: print(something)i-1fun1(i) fun1(5) # 这样就会打印五遍 somethingsomething something something something something要让递归正常工作&am…

IDEA2024.2重磅发布,更新完有4G!

JetBrains 今天宣布了其 IDE 家族版本之 2024.2 更新&#xff0c;其亮点是新 UI 现在已是默认设置&#xff0c;并且对 AI Assistant &#xff08;AI助手&#xff09;进行了几项改进。 安装密道 新 UI 的设计更加简约&#xff0c;可以根据需要以视觉方式扩展复杂功能。值得开发…