QT实现 WebsocketServer端与WebsocketClient 端通信

news2024/11/8 23:01:06

概 述

WebSockets 是一种通过单个 TCP 连接提供全双工通信信道的 web 技术。2011年,IETF 将 WebSocket 协议标准化为 RFC 6455 。Qt 提供的 QWebSocket 既可以用于客户端应用程序,也可以用于服务端应用程序,接口大部分和 QTcpSocket 一致。
QWebSocket 当前不支持 WebSocket 扩展和 WebSocket 子协议,仅支持 WebSocket 协议的版本13 (如 RFC 6455 中所述)。

QWebSocketServer的基本使用

要使用 Qt 的 WebSocket 模块,先在 pro 文件中加上 websockets:

QT += websockets

运行界面如下:
在这里插入图片描述
创建QWebSocketServer 对象创建

 m_WebSocketServer = new QWebSocketServer(u8"server", QWebSocketServer::NonSecureMode);

启动webSocketServer 的监听
请在监听客户端连接事件响应。

    if (m_WebSocketServer->listen(QHostAddress(ip), port.toInt()))
    {
        ui.textEdit_RecvMsg->append(u8"服务开启成功");
        ui.btnOpenServer->setEnabled(false);
        connect(m_WebSocketServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
    }
    else
    {
        QMessageBox::information(this, u8"提示", u8"监听失败, 是否开启了代理,或者IP错误");
    }

客户端连接后响应函数处理

void WebsocketServerDemo::onNewConnection()
{
    pSocket = m_WebSocketServer->nextPendingConnection();
    m_clients << pSocket;

    connect(pSocket, SIGNAL(textMessageReceived(QString)), this, SLOT(processTextMessage(QString)));
    connect(pSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));

    QString peerName = pSocket->requestUrl().toString();
    cout << "peerName = " << peerName.toStdString() << endl;

    //将ip和socket保存到map
    mapSocket[peerName] = pSocket;

    ui.listWidget_OnlineUser->addItem(peerName);
}

消息处理函数

//处理接收到的消息
void WebsocketServerDemo::processTextMessage(QString message) 
{
    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
    QString item = pSocket->requestUrl().toString();
    ui.textEdit_RecvMsg->append(time + "" + item + "\n" + message);

    //处理消息转发
    //...

}

客户端断开连接处理函数

//客户端连接断开的操作
void WebsocketServerDemo::socketDisconnected() 
{
    for (auto sk : m_clients)
    {
        if (!sk->isValid())
        {
            QString temp_key;
            ui.textEdit_RecvMsg->append("map size = " + QString(mapSocket.size()) + "\n");
            for (auto it = mapSocket.begin(); it!=mapSocket.end(); it++)
            {
                if (it.value() == sk)
                {
                    //删除项
                    QList<QListWidgetItem*> list;
                    list = ui.listWidget_OnlineUser-> findItems(it.key(), Qt::MatchCaseSensitive);

                    QListWidgetItem* sel = list[0];
                    int r = ui.listWidget_OnlineUser->row(sel);

                    QListWidgetItem* item = ui.listWidget_OnlineUser->takeItem(r);
                    ui.listWidget_OnlineUser->removeItemWidget(item);

                    delete item;
                    m_clients.removeOne(sk);

                    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
                    ui.textEdit_RecvMsg->append(time + "" + it.key() + "下线了\n");

                    temp_key = it.key();
                }
            }

            mapSocket.remove(temp_key);
            ui.textEdit_RecvMsg->append("after remove, map size = " + QString(mapSocket.size()) + "\n");
        }
    }
}

变量和参数定义

#include <QtWidgets/QWidget>
#include "ui_WebsocketServer.h"
#include <QWebSocketServer>
#include <QWebSocket>
#include <QMap>

class WebsocketServerDemo : public QWidget
{
    Q_OBJECT

public:
    WebsocketServerDemo(QWidget *parent = Q_NULLPTR);
    ~WebsocketServerDemo();

private slots:
    void on_btnOpenServer_clicked();
    void on_btnCloseServer_clicked();
    void on_btnSend_clicked();

    void onNewConnection();
    void processTextMessage(QString message);
    void socketDisconnected();

private:
    Ui::WebsocketServerClass ui;

    QWebSocketServer* m_WebSocketServer = nullptr;

    QList<QWebSocket*> m_clients;
    bool m_debug;
    QWebSocket* pSocket;
    QDateTime* current_date_time;
    QMap<QString, QWebSocket*> mapSocket;
};

QWebSocketClinet的基本使用

对于客户端,只需要指定服务端的 Url。通过 open 函数连接服务端的 Url ,使用 close 关闭连接。数据到来的时候有 textMessageReceived 和 binaryMessageReceived 等信号触发,也可以调用 sendTextMessage 或 sendBinaryMessage 发送数据。
在这里插入图片描述

连接服务器并监听连接、断开、消息接收消息的函数。

    m_websocket.open(url);
    connect(&m_websocket, SIGNAL(connected()), this, SLOT(onconnected()));
    connect(&m_websocket, SIGNAL(disconnected()), this, SLOT(closeConnection()));
    connect(&m_websocket, SIGNAL(textMessageReceived(QString)), this, SLOT(onTextMessageReceived(QString)));

客户端连接函数处理

//连接上之后
void WebSocketClientDemo::onconnected() 
{
    ui.label_ConnectStatus->setText(tr("connected"));
    ui.btnConnect->setEnabled(false);
    ui.btnDisconnect->setEnabled(true);
}

客户端函数处理
主要处理的是界面上的显示

//断开连接操作
void WebSocketClientDemo::closeConnection() 
{   
    ui.label_ConnectStatus->setText("disconnected");
}

消息接收处理

//收到消息
void WebSocketClientDemo::onTextMessageReceived(const QString& message)
{
    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
    ui.textEdit_recv->setText(time + "\n" + message);
}

变量和参数定义

#include <QtWidgets/QWidget>
#include "ui_WebSocketClientDemo.h"
#include <QLineEdit>
#include <QLabel>
#include <QTextEdit>
#include <QListWidget>
#include <QPushButton>
#include <QSpinBox>
#include <QButtonGroup>
#include <QObject>
#include <QWidget>
#include <QUrl>
#include <time.h>
#include <QByteArray>
#include <QWebSocket>

class WebSocketClientDemo : public QWidget
{
    Q_OBJECT

public:
    WebSocketClientDemo(QWidget *parent = Q_NULLPTR);
    ~WebSocketClientDemo();

private slots:
    void on_btnConnect_clicked();
    void on_btnDisconnect_clicked();
    void on_btnSend_clicked();

    void onconnected();
    void onTextMessageReceived(const QString& message);
    void closeConnection();    

private:
    Ui::WebSocketClientDemoClass ui;

    QUrl m_url;
    QWebSocket m_websocket;
    bool m_debug;
    QDateTime* current_date_time;
};

总结:

1、该示例代码简单实现了webSocketServer的创建。但是并没有用到多线程的技术,所以对并发处理不不适合。

2、本示例对数据处理,和错误事件并没有很好的解析,这需要后续实现。

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

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

相关文章

R语言机器学习方法在生态经济学领域中的应用

近年来&#xff0c;人工智能领域已经取得突破性进展&#xff0c;对经济社会各个领域都产生了重大影响&#xff0c;结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一&#xff0c;目前也在飞快的融入计量经济学研究。表面上机器学习通常使用大数据&#xf…

MoviePy介绍

MoivePy是一个用于视频编辑的Python库&#xff0c;可以&#xff1a;剪切、拼接、标题插入、视频合成、视频处理和创建自定义效果。它支持Windows、Linux、Mac&#xff0c;源码地址&#xff1a;https://github.com/Zulko/moviepy&#xff0c;最新发布版本v1.0.3&#xff0c;lice…

Qt(C++)开发一款图片防盗用水印制作小工具

一、前言 文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文…

[小白教程] Javascript Callback以及Promise/async/await 一文通

一、最初 一切从 Javascript 是一门异步编程语言说起&#xff0c;比如这种最简单的&#xff1a; let n 0function f1() {setTimeout(function () {n}, 1000)}f1()console.log(n)可能直觉上会觉得最终n1&#xff0c;但实际上打印出来的是0&#xff0c;因为尽管调用了f1函数&am…

vue笔记——实现打印功能1

第一步&#xff1a;安装vue-print-nb,打开项目终端输入 npm install vue-print-nb --save 第二步&#xff1a;打开package.json文件&#xff0c;在dependencies中出现vue-print-nb&#xff0c;说明安装成功&#xff0c;如下图所示。 第三步&#xff1a; 方法一&#xff1a;全…

电子科技大学计算机系统结构复习笔记(二):指令系统

目录 前言 重点一览 指令集系统结构&#xff08;ISA&#xff09;的分类 分类依据 存储结构 区别 图示 通用寄存器系统结构分类 存储器寻址 概述 寻址方式 MIPS寻址模式 小结 操作数类型 指令操作 与指令编码 常用操作数类型 常用指令系统的操作 常用指令系统编…

【Pytorch基础教程40】DLRM推荐算法模型部署

note 文章目录 note一、DLRM模型1. 特征工程和embedding层2. butterfly shuffle3. 模型结构 二、模型部署Reference 一、DLRM模型 DLRM是2020年meta提出的工业界推荐算法模型&#xff0c;模型结构非常简单&#xff0c;也没用到什么attention机制等的东西&#xff0c;更多是注重…

权限维持-关于影子用户

前言 影子用户相信大家都是比较熟悉&#xff0c;是一种权限维持的好方法。 注&#xff1a;单机和域环境都可以使用&#xff0c;但是域中可能没有那么好用。 复现 一.本地 1. 正常的影子用户 我们在cmd命令中在生成用户时&#xff0c;在用户名后面加上$就可以 net user test$ …

【cfeng work】什么是SaaS? SaaS详细介绍

WorkProj 内容管理 SaaSSaaS的优势SaaS的注意项SaaS产品核心组件cfeng结合work理解SaaS 本文introduce SaaS的相关内容 昨天cfeng已经介绍过云原生了&#xff0c;其实就是应用在设计上就要围绕Cloud&#xff0c;代表技术就是容器化和微服务、DevOps和区别于传统瀑布模型的持续更…

【Linux】——多线程

目录 Linux线程概念 二级页表 线程的优点 线程的缺点 线程异常 线程的用途 Linux中的线程和进程 进程和线程 进程的多个线程共享 进程和线程的关系 Linux线程控制 POSIX线程库 线程创建 线程ID及地址空间布局 线程等待 线程终止 Linux线程概念 什…

华为OD机试真题 Java 实现【找终点】【2023 B卷 100分】,附详细解题思路

一、题目描述 给定一个正整数数组&#xff0c;设为nums&#xff0c;最大为100个成员&#xff0c;求从第一个成员开始&#xff0c;正好走到数组最后一个成员&#xff0c;所使用的最少步骤数。 要求&#xff1a; 第一步必须从第一元素开始&#xff0c;且1 < 第一步的步长 &…

初出茅庐的小李博客之CAN通信基础知识

CAN是什么&#xff1f; CAN 是 Controller Area Network 的缩写&#xff0c;中文是控制器局域网路,是 ISO 国际标准化的串行通信协议之一。 CAN:控制器局域网( Controller Area Network)属于现场总线的范畴&#xff0c;是一种有效支持分布式控制系统的串行通信网络 CAN是由德…

MySQL Windows 64位解压版安装

1、下载MySQL安装包 下载地址&#xff1a;MySQL :: Download MySQL Community Server (Archived Versions) 选择安装版本&#xff1a;我选择的是5.1.43的版本&#xff0c;下载到本地&#xff0c;并解压到自己想要放的位置&#xff0c;比如&#xff1a;D:\soft 2、在D:\soft\m…

S7-200 PLC新特性是什么

更多关于西门子S7-200PLC内容请查看&#xff1a;西门子200系列PLC学习课程大纲(课程筹备中) 西门子200PLC能做什么&#xff1f; 它可以控制设备&#xff0c;实现自动控制&#xff0c;比如切割机&#xff0c;木雕刻机&#xff0c;写字机&#xff0c;锅炉的自动控制等等&#xf…

vscode工具使用

语言的使用&#xff1a; 安装chinse Lagnuage插件 关于设置 (1) 通过可视化界面的方式设置&#xff0c;File -> Preferences -> Settings 快捷键&#xff1a;ctrl , (<)打开 ctrl F4 关闭 (2) 通过json配置文件方式设置&#xff0c;ctrlshiftp, 选择Open …

c++继承详解

前言 继承是类复用的重要方式&#xff0c;学习面向对象语言时学习继承是必不可少的&#xff0c;在c中继承机制一种较为复杂的机制&#xff0c;下面让我们一起来认识一下c中的继承。 目录 1.继承的概念和定义 1.1继承的概念 1.2 继承的定义 2.基类和派生类之间的转换 3.继承…

基于html+css的图展示106

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

PCL点云处理之分层切片法计算树冠投影面积 (一百七十四)

PCL点云处理之分层切片法计算树冠投影面积 (一百七十四) 一、算法介绍二、方法流程三、具体实验1.代码2.效果四、算法总结一、算法介绍 在上一节中,通过树冠整体投影到同一水平面后,计算凸包面积,粗略估计了树冠投影面积,但在通常的研究学习中,这种方法较为笼统,大部分…

springboot配置使用redis序列化时报错“无法自动装配。找不到 ‘RedisConnectionFactory‘ 类型的 Bean”

今天在使用springboot操作redis时出现乱码的问题 像这样&#xff0c;这里对应的key明实际上时springboot:string 对应的值时徐浩的redis 但是当向redis推送数据时就乱码了&#xff0c;后面一查是因为在springboot-redis中&#xff0c;默认配置没有序列化&#xff0c;直接将str…

Python词云绘制

Python词云绘制 效果展示以及准备工作&#xff1a;进入代码书写 效果展示以及准备工作&#xff1a; 效果展示图&#xff1a; 准备工作 pycharm安装第三方库numpy,jieba,wordcloud词云文本的准备&#xff08;.txt&#xff09;背景图的准备&#xff08;我是用的PS&#xff09;…