目錄
前言
一、服務(wù)器的代碼:
1、服務(wù)器的思路
2、具體服務(wù)器的代碼示例
二、客戶端的代碼:
1、客戶端的思路(和服務(wù)器類似)
2、具體客戶端的代碼示例
前言
????????要是想了解QWebSocket的詳細(xì)知識(shí),還得移步到上一篇文章:
WebSocket 詳解,以及用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(含代碼例子)-CSDN博客
????????本篇文章主要講解如何利用QWebSocket?實(shí)現(xiàn)服務(wù)和客戶之間的通訊
一、服務(wù)器的代碼:
1、服務(wù)器的思路
(1)首先創(chuàng)建了一個(gè)服務(wù)器的基類,主要實(shí)現(xiàn)了服務(wù)類的基本接口:
1、創(chuàng)建服務(wù)器:new QWebSocketServer
2、監(jiān)聽(tīng):listen
m_pWebSocketServer->listen(QHostAddress::LocalHost, mPort);//端口號(hào)
3、有新的連接,收到這個(gè)信號(hào):QWebSocketServer::newConnection
4、獲得新的客戶端:nextPendingConnection?
5、接收到信息時(shí)候,收到信號(hào):QWebSocket::binaryMessageReceived?
6、斷開(kāi)連接,收到信號(hào):QWebSocket::disconnected注意:數(shù)據(jù)的接收和發(fā)送,有兩種格式,二進(jìn)制和文本的,具體按照實(shí)際需要的來(lái)選擇;
(2)在服務(wù)器的基類上,封裝一個(gè)具體使用的類,這個(gè)類,主要是添加了QThread,創(chuàng)建一個(gè)子線程來(lái)進(jìn)行服務(wù)器的開(kāi)啟,監(jiān)聽(tīng)和接收數(shù)據(jù),不會(huì)影響主線程的事件。
2、具體服務(wù)器的代碼示例
????????接收和發(fā)送的數(shù)據(jù),以二進(jìn)制為例
(1)服務(wù)器基類:
服務(wù)器基類的頭文件:
? ? ? ? 1)開(kāi)啟一個(gè)端口號(hào)為“9000”的服務(wù)器
? ? ? ? 2)監(jiān)聽(tīng)的網(wǎng)路是:QHostAddress::Any
QHostAddress::Any表示服務(wù)端監(jiān)聽(tīng)所有可用的網(wǎng)絡(luò)接口。
它是一個(gè)特殊的IP地址,表示服務(wù)端可以接受來(lái)自任何IP地址的連接請(qǐng)求。
這通常用于在一個(gè)計(jì)算機(jī)上運(yùn)行多個(gè)網(wǎng)絡(luò)服務(wù)時(shí),讓服務(wù)端能夠監(jiān)聽(tīng)所有可用的網(wǎng)絡(luò)接口,以便接受來(lái)自不同網(wǎng)絡(luò)接口的連接請(qǐng)求。
注意:也可以監(jiān)聽(tīng)具體的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:
//客戶端發(fā)來(lái)的數(shù)據(jù)
void sigProcessServerMessage(const QByteArray &data);
public slots:
//發(fā)送數(shù)據(jù)給客戶端
void slotSendToAllClients(const QByteArray &data);
//啟動(dòng)websocket服務(wù)器
void slotStartServer();
private slots:
//處理新接入的連接
void slotNewConnection();
//處理鏈接斷開(kāi)的事件
void slotSocketDisconnected();
//接收數(shù)據(jù),并轉(zhuǎn)發(fā)
void slotProcessBinaryMessage(const QByteArray &message);
public:
//檢測(cè)是否存在客戶端
bool hadClients();
private:
QWebSocketServer *m_pWebSocketServer = nullptr;
QList<QWebSocket *> m_clients;
unsigned short m_nPort = 9000;
QString m_strServerName = "server";
};
#endif // WEBSOCKETSERVERBASE_H
服務(wù)器基類的源文件:
#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();
}
}
//接收到外部發(fā)來(lái)的信息,轉(zhuǎn)發(fā)給客戶端
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);
//二進(jìn)制數(shù)據(jù)的接收
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();
}
}
//接收客戶端發(fā)來(lái)的數(shù)據(jù),并轉(zhuǎn)發(fā)出去
void WebsocketServerBase::slotProcessBinaryMessage(const QByteArray &data)
{
qDebug() << __FUNCTION__ << " data:" << data;
emit sigProcessServerMessage(data);
//test
//slotSendToAllClients(data);
}
(2)將服務(wù)器基類封裝,改造下:(外面可以直接使用這個(gè)類進(jìn)行通訊)
改造后服務(wù)器的頭文件:
????????此處本例是使用回調(diào)函數(shù)將結(jié)果拋給上一層調(diào)用者,在qt里,完全可以用信號(hào)槽代替的。
#ifndef READERWEBSOCKETSERVER_H
#define READERWEBSOCKETSERVER_H
#include <QObject>
#include "Singleton.h"
// 回調(diào)函數(shù),將websocket的結(jié)果拋給上層
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:
// 設(shè)置回調(diào)函數(shù)
void setCallBack(recvMsgToSerial pFunc, void* pUser = NULL);
// 接收串口發(fā)來(lái)數(shù)據(jù),轉(zhuǎn)發(fā)給客戶端
bool sendData(const QByteArray &byteArray);
signals:
//轉(zhuǎn)發(fā)數(shù)據(jù)給客戶端
void sigSendToAllClients(const QByteArray &data);
private slots:
//處理客戶端發(fā)來(lái)的數(shù)據(jù),轉(zhuǎn)發(fā)給需要的地方
void slotProcessServerMessage(const QByteArray &data);
private:
WebsocketServerBase* m_pWsServer = nullptr;
QThread* m_thdWsServer = nullptr;
void* m_pUser; // 返回回調(diào)的對(duì)象
recvMsgToSerial m_pRecvMsgToSerial; // 回調(diào)
};
#endif // READERWEBSOCKETSERVER_H
改造后服務(wù)器的源文件:
#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;
}
//接收串口發(fā)來(lái)數(shù)據(jù),轉(zhuǎn)發(fā)給客戶端
bool ReaderWebsocketServer::sendData(const QByteArray &byteArray)
{
bool hadBnode = m_pWsServer->hadClients();
if (hadBnode)
{
emit sigSendToAllClients(byteArray);
}
}
//處理客戶端發(fā)來(lái)的數(shù)據(jù),轉(zhuǎn)發(fā)給需要的地方
void ReaderWebsocketServer::slotProcessServerMessage(const QByteArray &byteArray)
{
qDebug() << __FUNCTION__ ;
m_pRecvMsgToSerial(byteArray);
}
二、客戶端的代碼:
1、客戶端的思路(和服務(wù)器類似)
(1)首先創(chuàng)建了一個(gè)客戶端的基類,主要實(shí)現(xiàn)了客戶端的基本接口:
(2)在客戶端基類上,封裝一個(gè)具體使用的類:(外面可以直接使用這個(gè)類進(jìn)行通訊)
????????這個(gè)類,主要是添加了QThread 和QTimer,QThread 創(chuàng)建一個(gè)子線程來(lái)進(jìn)行服務(wù)器的開(kāi)啟,監(jiān)聽(tīng)和接收數(shù)據(jù),不會(huì)影響主線程的事件;QTimer主要是發(fā)心跳包,實(shí)現(xiàn)斷開(kāi)重連機(jī)制;
2、具體客戶端的代碼示例
????????接收和發(fā)送的數(shù)據(jù),以二進(jìn)制為例
(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的信號(hào)函數(shù)
public slots:
void slotCreateDataRecWS();//創(chuàng)建websocket連接
void slotSendBinaryMessageMessage(const QByteArray &byteArray);
void slotReconnect(); /*-<周期重連函數(shù) */
void slotActiveReconnect();
private slots:
void slotOnConnected(); /*-<socket建立成功后,觸發(fā)該函數(shù) */
void slotOnBinaryMessageReceived(const QByteArray &byteArray); /*-<收到Sev端的數(shù)據(jù)時(shí),觸發(fā)該函數(shù) */
void slotOnDisConnected(); /*-<socket連接斷開(kāi)后,觸發(fā)該函數(shù) */
private:
QWebSocket *m_pDataRecvWS; /*-<websocket類 */
QTimer *m_pTimer; /*-<周期重連Timer */
QString m_strURL; /*連接URL*/
bool m_bConnectStatus; /*-<websocket連接狀態(tài),連接成功:true;斷開(kāi):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);/*-<當(dāng)連接失敗時(shí),觸發(fā)重連計(jì)時(shí)器,設(shè)置計(jì)數(shù)周期為3秒 */
}
void WebSocketBase::slotOnBinaryMessageReceived(const QByteArray& byteArray)
{
m_byteArray = byteArray;
}
(2)將客戶端基類封裝,改造下:(外面可以直接使用這個(gè)類進(jìn)行通訊)
改造后客戶端頭文件:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-807807.html
/*
* @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:
//轉(zhuǎn)發(fā)數(shù)據(jù)給server
void sigSendToServer(const QByteArray &byteArray);
public slots:
//接收服務(wù)器數(shù)據(jù)
void slotRecvServerData(const QByteArray &byteArray);
//發(fā)送服務(wù)器心跳包
void slotHeartBeatToServer();
private:
void readConfig();
private:
WebSocketBase* m_wsReaderClient;
QThread* m_thdReaderClient;
QTimer *m_pTimerReader;
int m_nHeartBeatTimeOutReader;
QString m_URL = "";
};
改造后客戶端源文件:文章來(lái)源地址http://www.zghlxwxcb.cn/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();
}
到了這里,關(guān)于(二) 用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(詳細(xì)代碼直接使用)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!