(二) 用QWebSocket 实现服务端和客户端(详细代码直接使用)

这篇具有很好参考价值的文章主要介绍了(二) 用QWebSocket 实现服务端和客户端(详细代码直接使用)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一、服务器的代码:

1、服务器的思路

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

二、客户端的代码:

1、客户端的思路(和服务器类似)

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


前言

        要是想了解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

服务器基类的源文件:

#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);
}

(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

改造后服务器的源文件:

#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、客户端的思路(和服务器类似)

(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;
};

客户端基类的源文件:

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

WebSocketBase::WebSocketBase(QObject *parent) : QObject(parent)
  ,m_pDataRecvWS(nullptr)
  ,m_pTimer(nullptr)
  ,m_strURL("")
  ,m_bConnectStatus(false)
  ,m_byteArray("")
{

}

WebSocketBase::~WebSocketBase()
{
    m_pTimer->stop();
    m_pTimer->deleteLater();
    m_pDataRecvWS->abort();
    m_pDataRecvWS->deleteLater();
}

void WebSocketBase::setWebSocketUrl(QString strUrl)
{
    m_strURL = strUrl;
    if(m_strURL.isEmpty())
    {
        m_strURL = "127.0.0.1";
    }
}

bool WebSocketBase::getConnectStatus()
{
    return m_bConnectStatus;
}

int WebSocketBase::RecvFrom(QByteArray &byteArray)
{
    byteArray = m_byteArray;
    m_byteArray.clear();
    return byteArray.size();
}

void WebSocketBase::slotCreateDataRecWS()
{
    if(nullptr == m_pTimer)
    {
        m_pTimer = new QTimer();
    }

    qDebug() << "Server Address" << m_strURL;

    if(m_pDataRecvWS == nullptr)
    {
        m_pDataRecvWS = new QWebSocket();
        connect(m_pDataRecvWS, &QWebSocket::disconnected, this, &WebSocketBase::slotOnDisConnected);
        connect(m_pDataRecvWS, &QWebSocket::binaryMessageReceived, this, &WebSocketBase::slotOnBinaryMessageReceived);
        connect(m_pDataRecvWS, &QWebSocket::connected, this, &WebSocketBase::slotOnConnected);
        connect(m_pTimer, &QTimer::timeout, this, &WebSocketBase::slotReconnect);
        m_pDataRecvWS->open(QUrl(m_strURL));
    }
}

void WebSocketBase::slotSendBinaryMessageMessage(const QByteArray &message)
{
    if (m_pDataRecvWS)
        m_pDataRecvWS->sendBinaryMessage(message);
}

void WebSocketBase::slotActiveReconnect()
{
    qDebug("try to Active Reconnect!!!");
    if(m_pDataRecvWS != nullptr)
    {
        m_bConnectStatus = false;
        m_pDataRecvWS->abort();
        qDebug("Exec Active Reconnect!");
        m_pDataRecvWS->open(QUrl(m_strURL));
    }

    return;
}

void WebSocketBase::slotReconnect()
{
    qDebug() << "try to reconnect:" << m_strURL;

    m_pDataRecvWS->abort();
    m_pDataRecvWS->open(QUrl(m_strURL));
}

void WebSocketBase::slotOnConnected()
{
    qDebug("WebSocketBase websocket is already connect!");

    m_bConnectStatus = true;
    m_pTimer->stop();
    qDebug() << "Address:" << m_strURL;
}

void WebSocketBase::slotOnDisConnected()
{
    qDebug() << "Address is disconnected:" << m_strURL;

    m_bConnectStatus = false;
    m_pTimer->start(3000);/*-<当连接失败时,触发重连计时器,设置计数周期为3秒 */
}

void WebSocketBase::slotOnBinaryMessageReceived(const QByteArray& byteArray)
{
    m_byteArray = byteArray;
}

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

改造后客户端头文件:

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

#include <QObject>
#include <QCoreApplication>

#include "Singleton.h"

class WebSocketBase;
class QTimer;

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

public:
    WsReaderClient(QObject *parent = nullptr);
    ~WsReaderClient();

public:
    void SendTo(const QByteArray &byteArray);
    int RecvFrom(QByteArray& byteArray);

    bool getConnectStatus();

signals:
    //转发数据给server
    void sigSendToServer(const QByteArray &byteArray);

public slots:
    //接收服务器数据
    void slotRecvServerData(const QByteArray &byteArray);

    //发送服务器心跳包
    void slotHeartBeatToServer();

private:
    void readConfig();

private:
    WebSocketBase* m_wsReaderClient;
    QThread* m_thdReaderClient;
    QTimer *m_pTimerReader;
    int m_nHeartBeatTimeOutReader;
    QString m_URL = "";
};

改造后客户端源文件:文章来源地址https://www.toymoban.com/news/detail-807807.html

#include "WsReaderClient.h"

#include <QWebSocket>
#include <QTimer>
#include <QThread>
#include <QByteArray>
#include <cstring>
#include <QSettings>

#include "WebSocketBase.h"

WsReaderClient::WsReaderClient(QObject *parent)
    : QObject(parent)
{
    readConfig();

    m_thdReaderClient = new QThread();
    m_wsReaderClient = new WebSocketBase();
    m_wsReaderClient->setWebSocketUrl(m_URL);

    m_wsReaderClient->moveToThread(m_thdReaderClient);
    connect(m_thdReaderClient, &QThread::started, m_wsReaderClient, &WebSocketBase::slotCreateDataRecWS);
    connect(this, &WsReaderClient::sigSendToServer, m_wsReaderClient, &WebSocketBase::slotSendBinaryMessageMessage);
    //connect(this, &WsReaderClient::sigReconnectServer, m_wsReaderClient, &WebSocketBase::slotActiveReconnect);

    connect(m_thdReaderClient, &QThread::finished, m_wsReaderClient, &WebSocketBase::deleteLater);
    connect(m_thdReaderClient, &QThread::finished, m_thdReaderClient, &QThread::deleteLater);
    m_thdReaderClient->start();

    m_pTimerReader = new QTimer(this);
    connect(m_pTimerReader, &QTimer::timeout, this, &WsReaderClient::slotHeartBeatToServer);
    //m_nHeartBeatTimeOutKeyBoard = 0;
    m_pTimerReader->start(10*1000);
}

WsReaderClient::~WsReaderClient()
{
    m_pTimerReader->stop();
    m_pTimerReader->deleteLater();

    if(m_wsReaderClient)
    {
       delete m_wsReaderClient;
        m_wsReaderClient = nullptr;
    }

    if(m_pTimerReader)
    {
        delete m_pTimerReader;
        m_pTimerReader = nullptr;
    }
}

void WsReaderClient::slotHeartBeatToServer()
{
    //todo
}

void WsReaderClient::readConfig()
{
    // "/mnt/hgfs/SharedFiles/shanxi/Reader/linux_readerTest/bin/libReaderApi.so";
    QString appPath = QCoreApplication::applicationDirPath();
    qDebug() << "appPath=" << appPath;

    QString path = appPath + "/ReaderConfig.ini";
    QSettings settings(path, QSettings::IniFormat);
    m_URL = settings.value("Communication/ipAddr").toString();
    qDebug() << "m_URL=" << m_URL;
}

void WsReaderClient::SendTo(const QByteArray &data)
{
    emit sigSendToServer(data);
}

int WsReaderClient::RecvFrom(QByteArray &byteArray)
{
    return m_wsReaderClient->RecvFrom(byteArray);
}

bool WsReaderClient::getConnectStatus()
{
    return m_wsReaderClient->getConnectStatus();
}

到了这里,关于(二) 用QWebSocket 实现服务端和客户端(详细代码直接使用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • netty的TCP服务端和客户端实现

    2024年02月21日
    浏览(35)
  • C++实现WebSocket通信(服务端和客户端)

    天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。 这里单纯是个人总结,如需更官方更准确的websocket介绍可百度 websocket是一种即时通讯协

    2024年02月09日
    浏览(33)
  • Golang实现之TCP长连接-------服务端和客户端

    一、数据包的数据结构 (所有字段采用大端序) 帧头 帧长度(头至尾) 帧类型 帧数据 帧尾 1字节 4字节 2字节 1024字节 1字节 byte int short string byte 0xC8 0xC9 二、Server端 实现代码 1、main.go 2、server.go 3、protocol.go 4、response.go 5、result.go 三、Client端 实现代码

    2024年02月07日
    浏览(39)
  • 【Qt专栏】Qt实现TCP服务端和客户端通信

    网络通信是程序员必须会的一项生存技能,这里简单的实现了服务端和客户端通信的两个小示例,代码可以直接拿来用,开发环境是Qt5.9.6。 1.项目架构 2.tcpserver.h文件 3.tcpserver.cpp文件 4.测试效果 1.项目架构 2.tcpserver.h文件 3.tcpserver.cpp文件 4.测试效果 好了,两个小程序写完并

    2024年02月12日
    浏览(28)
  • SpringBoot+CAS整合服务端和客户端实现SSO单点登录与登出快速入门上手

    教学讲解视频地址:视频地址 因为CAS支持HTTP请求访问,而我们是快速入门上手视频,所以这期教程就不教大家如何配置HTTPS了,如果需要使用HTTPS,可以参考其他博客去云服务器申请证书或者使用JDK自行生成一个证书。 下载CAS Server(直接下载压缩包就可以) 这里我们用的是

    2024年02月02日
    浏览(46)
  • 《TCP/IP网络编程》阅读笔记--基于Windows实现Hello Word服务器端和客户端

    目录 1--Hello Word服务器端 2--客户端 3--编译运行 3-1--编译服务器端 3-2--编译客户端 3-3--运行 运行结果:

    2024年02月10日
    浏览(44)
  • Linux中UDP服务端和客户端

    2024年02月13日
    浏览(30)
  • UDP服务端和客户端通信代码开发流程

    TCP: 传输控制协议,面向连接的,稳定的,可靠的,安全的数据集流传递 稳定和可靠:丢包重传 数据有序:序号和确认序号 流量控制:稳定窗口 UDP :用户数据报协议 面向无连接的,不稳定的,不可靠,不安全的数据报传递=---更像是收发短信,UDP传输不需要建立连接,传输效率更高

    2024年02月06日
    浏览(33)
  • Nacos源码 (5) Grpc服务端和客户端

    Nacos 2.x在服务端与客户端直接增加了GRPC通信方式,本文通过2.0.2版本源码,简单分析GRPC通信方式: 服务器启动 客户端连接 客户端心跳 服务器监控检查 api/src/main/proto/nacos_grpc_service.proto文件: 文件定义了通信层的service和message结构,业务层请求响应的序列化和反序列化是Na

    2024年02月10日
    浏览(35)
  • 网络编程——socket服务端和客户端(TCP)

    所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通

    2024年02月07日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包