当前位置:   article > 正文

2024年最新(二) 用QWebSocket 实现服务端和客户端(详细代码直接使用),一文详解_qwebsocketserver

qwebsocketserver

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

前言

要是想了解QWebSocket的详细知识,还得移步到上一篇文章:

WebSocket 详解,以及用QWebSocket 实现服务端和客户端(含代码例子)-CSDN博客

本篇文章主要讲解如何利用QWebSocket 实现服务和客户之间的通讯

一、服务器的代码:
1、服务器的思路

(1)首先创建了一个服务器的基类,主要实现了服务类的基本接口:

1、创建服务器:new QWebSocketServer
2、监听:listen
m_pWebSocketServer->listen(QHostAddress::LocalHost, mPort);//端口号
3、有新的连接,收到这个信号:QWebSocketServer::newConnection
4、获得新的客户端:nextPendingConnection 
5、接收到信息时候,收到信号:QWebSocket::binaryMessageReceived 
6、断开连接,收到信号:QWebSocket::disconnected

注意:数据的接收和发送,有两种格式,二进制和文本的,具体按照实际需要的来选择;

(2)在服务器的基类上,封装一个具体使用的类,这个类,主要是添加了QThread,创建一个子线程来进行服务器的开启,监听和接收数据,不会影响主线程的事件。

2、具体服务器的代码示例

接收和发送的数据,以二进制为例

(1)服务器基类:

服务器基类的头文件:

1)开启一个端口号为“9000”的服务器

2)监听的网路是:QHostAddress::Any

QHostAddress::Any表示服务端监听所有可用的网络接口。
它是一个特殊的IP地址,表示服务端可以接受来自任何IP地址的连接请求。
这通常用于在一个计算机上运行多个网络服务时,让服务端能够监听所有可用的网络接口,

以便接受来自不同网络接口的连接请求。

注意:也可以监听具体的IP地址:

例如:QHostAddress(strLocalHostIp)

#ifndef WEBSOCKETSERVERBASE_H
#define WEBSOCKETSERVERBASE_H

#include <QObject>
#include <QtWebSockets>

QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
QT_FORWARD_DECLARE_CLASS(QString)

class WebsocketServerBase : public QObject
{
    Q_OBJECT
public:
    explicit WebsocketServerBase(QString serverName,  quint16 port, QObject *parent = 0);
    virtual ~WebsocketServerBase();

signals:
    //客户端发来的数据
    void sigProcessServerMessage(const QByteArray &data);

public slots:
    //发送数据给客户端
    void slotSendToAllClients(const QByteArray &data);

    //启动websocket服务器
    void slotStartServer();

private slots:
    //处理新接入的连接
    void slotNewConnection();

    //处理链接断开的事件
    void slotSocketDisconnected();

    //接收数据,并转发
    void slotProcessBinaryMessage(const QByteArray &message);

public:
    //检测是否存在客户端
    bool hadClients();

private:
    QWebSocketServer *m_pWebSocketServer = nullptr;
    QList<QWebSocket *> m_clients;

    unsigned short m_nPort = 9000;
    QString m_strServerName = "server";
};

#endif // WEBSOCKETSERVERBASE_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

服务器基类的源文件:

#include "websocketserverbase.h"

#include<QDebug>

static QString getIdentifier(QWebSocket *peer)
{
    return QStringLiteral("%1:%2").arg(peer->peerAddress().toString(),
                                       peer->origin());
}

WebsocketServerBase::WebsocketServerBase(QString serverName,  quint16 port, QObject *parent)
    : QObject(parent)
    ,m_nPort(port)
    ,m_strServerName(serverName)
{
}

WebsocketServerBase::~WebsocketServerBase()
{   
    if(m_pWebSocketServer)
    {
        m_pWebSocketServer->close();
        //m_pWebSocketServer->abort();
        m_pWebSocketServer->deleteLater();
    }
}

//接收到外部发来的信息,转发给客户端
void WebsocketServerBase::slotSendToAllClients(const QByteArray &data)
{
    qDebug() << __FUNCTION__;

    for (QWebSocket *pClient : qAsConst(m_clients)) {
        qDebug() << "data: " << data;
         pClient->sendBinaryMessage(data);
    }
}

bool WebsocketServerBase::hadClients()
{
    return m_clients.size()>0;
}

void WebsocketServerBase::slotStartServer()
{
    if(m_pWebSocketServer)
        return;

    m_pWebSocketServer = new QWebSocketServer(m_strServerName, QWebSocketServer::NonSecureMode, this);

    if (m_pWebSocketServer->listen(QHostAddress::Any, m_nPort))
    {
        connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &WebsocketServerBase::slotNewConnection);
        qDebug() << "WebSocket is start, port:" << m_nPort;
    }
}

void WebsocketServerBase::slotNewConnection()
{
    auto pSocket = m_pWebSocketServer->nextPendingConnection();
    QTextStream(stdout) << getIdentifier(pSocket) << " connected!\n";

    qDebug() << "client connected!";

    pSocket->setParent(this);

	//二进制数据的接收
    connect(pSocket, &QWebSocket::binaryMessageReceived, this, &WebsocketServerBase::slotProcessBinaryMessage);
    connect(pSocket, &QWebSocket::disconnected, this, &WebsocketServerBase::slotSocketDisconnected);

    m_clients << pSocket;
}

void WebsocketServerBase::slotSocketDisconnected()
{
	QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
	QTextStream(stdout) << getIdentifier(pClient) << " disconnected!\n";
	if (pClient)
	{
		m_clients.removeAll(pClient);
		pClient->deleteLater();
	}
}

//接收客户端发来的数据,并转发出去
void WebsocketServerBase::slotProcessBinaryMessage(const QByteArray &data)
{
    qDebug() << __FUNCTION__ << " data:" << data;
    emit sigProcessServerMessage(data);

    //test
    //slotSendToAllClients(data);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

(2)将服务器基类封装,改造下:(外面可以直接使用这个类进行通讯)

改造后服务器的头文件:

此处本例是使用回调函数将结果抛给上一层调用者,在qt里,完全可以用信号槽代替的。

#ifndef READERWEBSOCKETSERVER_H
#define READERWEBSOCKETSERVER_H

#include <QObject>
#include "Singleton.h"


// 回调函数,将websocket的结果抛给上层
typedef void(*recvMsgToSerial)(const QByteArray &byteArray);

class WebsocketServerBase;
class ReaderWebsocketServer : public QObject, public Singleton<ReaderWebsocketServer>
{
    Q_OBJECT
    friend class Singleton<ReaderWebsocketServer>;

public:
    explicit ReaderWebsocketServer(QObject *parent = 0);
    virtual ~ReaderWebsocketServer();

public:
    // 设置回调函数
    void setCallBack(recvMsgToSerial pFunc, void* pUser = NULL);

    // 接收串口发来数据,转发给客户端
    bool sendData(const QByteArray &byteArray);

signals:
	//转发数据给客户端
    void sigSendToAllClients(const QByteArray &data);

private slots:
    //处理客户端发来的数据,转发给需要的地方
    void slotProcessServerMessage(const QByteArray &data);

private:
    WebsocketServerBase* m_pWsServer = nullptr;
    QThread* m_thdWsServer = nullptr;

    void* m_pUser;							// 返回回调的对象
    recvMsgToSerial m_pRecvMsgToSerial;		// 回调
};

#endif // READERWEBSOCKETSERVER_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

改造后服务器的源文件:

#include "readerwebsocketserver.h"

#include <QThread>
#include <cstring>
#include "websocketserverbase.h"

ReaderWebsocketServer::ReaderWebsocketServer(QObject *parent)
    : QObject(parent)
{
    m_thdWsServer = new QThread();
    m_pWsServer = new WebsocketServerBase("reader", 9000);
    m_pWsServer->moveToThread(m_thdWsServer);

    connect(m_pWsServer, &WebsocketServerBase::sigProcessServerMessage, this, &ReaderWebsocketServer::slotProcessServerMessage);
    connect(this, &ReaderWebsocketServer::sigSendToAllClients, m_pWsServer, &WebsocketServerBase::slotSendToAllClients);

    connect(m_thdWsServer, &QThread::started, m_pWsServer, &WebsocketServerBase::slotStartServer);
    connect(m_thdWsServer, &QThread::finished, m_pWsServer, &WebsocketServerBase::deleteLater);
    connect(m_thdWsServer, &QThread::finished, m_thdWsServer, &WebsocketServerBase::deleteLater);
    m_thdWsServer->start();
}

ReaderWebsocketServer::~ReaderWebsocketServer()
{
    if(m_thdWsServer)
    {
        m_thdWsServer->quit();
        m_thdWsServer->wait();
    }

    if(m_pWsServer)
    {
        m_pWsServer->deleteLater();
    }
}

void ReaderWebsocketServer::setCallBack(recvMsgToSerial pFunc, void *pUser)
{
    if (nullptr != pFunc)
        m_pRecvMsgToSerial = pFunc;

    if (nullptr != pUser)
        m_pUser = pUser;
}

//接收串口发来数据,转发给客户端
bool ReaderWebsocketServer::sendData(const QByteArray &byteArray)
{
    bool hadBnode = m_pWsServer->hadClients();
    if (hadBnode)
    {
        emit sigSendToAllClients(byteArray);
    }
}

//处理客户端发来的数据,转发给需要的地方
void ReaderWebsocketServer::slotProcessServerMessage(const QByteArray &byteArray)
{
    qDebug() << __FUNCTION__ ;
    m_pRecvMsgToSerial(byteArray);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
二、客户端的代码:
1、客户端的思路(和服务器类似)

(1)首先创建了一个客户端的基类,主要实现了客户端的基本接口:

(2)在客户端基类上,封装一个具体使用的类:(外面可以直接使用这个类进行通讯)

这个类,主要是添加了QThread 和QTimer,QThread 创建一个子线程来进行服务器的开启,监听和接收数据,不会影响主线程的事件;QTimer主要是发心跳包,实现断开重连机制;

2、具体客户端的代码示例

接收和发送的数据,以二进制为例

(1)客户端基类:

客户端基类的头文件:

/*
 * @Description: websocket客户端,用于与中间件通信
 */

#pragma once
#include <QObject>
#include <QByteArray>

class QTimer;
class QWebSocket;
class WebSocketBase : public QObject
{
    Q_OBJECT
public:
    WebSocketBase(QObject *parent = nullptr);
    ~WebSocketBase();

    void setWebSocketUrl(QString strUrl="");
    bool getConnectStatus();
    int RecvFrom(QByteArray& byteArray);

signals:
    void sigClientBinaryMessageReceived(const QByteArray &byteArray); //借用websocket的信号函数

public slots:
    void slotCreateDataRecWS();//创建websocket连接
    void slotSendBinaryMessageMessage(const QByteArray &byteArray);
    void slotReconnect();           /*-<周期重连函数 */
    void slotActiveReconnect();

private slots:
    void slotOnConnected();                 /*-<socket建立成功后,触发该函数 */
    void slotOnBinaryMessageReceived(const QByteArray &byteArray);   /*-<收到Sev端的数据时,触发该函数 */
    void slotOnDisConnected();              /*-<socket连接断开后,触发该函数 */

private:
    QWebSocket *m_pDataRecvWS;     /*-<websocket类 */
    QTimer *m_pTimer;            /*-<周期重连Timer */
    QString m_strURL;              /*连接URL*/
    bool m_bConnectStatus;         /*-<websocket连接状态,连接成功:true;断开:false */
    QByteArray m_byteArray;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

客户端基类的源文件:

#include "WebSocketBase.h"
#include <QWebSocket>
#include <QTimer>
#include <QByteArray>


![img](https://img-blog.csdnimg.cn/img_convert/ee9cef75287ab9e76682d2a0bc89c1b2.png)
![img](https://img-blog.csdnimg.cn/img_convert/9894cd0ed8fd163575ea239b78b42882.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

Array;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

客户端基类的源文件:

#include "WebSocketBase.h"
#include <QWebSocket>
#include <QTimer>
#include <QByteArray>


[外链图片转存中...(img-shA8KnEV-1715675050058)]
[外链图片转存中...(img-i6Y4lhfc-1715675050058)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/884034
推荐阅读
相关标签
  

闽ICP备14008679号