当前位置:   article > 正文

(二) 用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)

  1. #ifndef WEBSOCKETSERVERBASE_H
  2. #define WEBSOCKETSERVERBASE_H
  3. #include <QObject>
  4. #include <QtWebSockets>
  5. QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
  6. QT_FORWARD_DECLARE_CLASS(QWebSocket)
  7. QT_FORWARD_DECLARE_CLASS(QString)
  8. class WebsocketServerBase : public QObject
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit WebsocketServerBase(QString serverName, quint16 port, QObject *parent = 0);
  13. virtual ~WebsocketServerBase();
  14. signals:
  15. //客户端发来的数据
  16. void sigProcessServerMessage(const QByteArray &data);
  17. public slots:
  18. //发送数据给客户端
  19. void slotSendToAllClients(const QByteArray &data);
  20. //启动websocket服务器
  21. void slotStartServer();
  22. private slots:
  23. //处理新接入的连接
  24. void slotNewConnection();
  25. //处理链接断开的事件
  26. void slotSocketDisconnected();
  27. //接收数据,并转发
  28. void slotProcessBinaryMessage(const QByteArray &message);
  29. public:
  30. //检测是否存在客户端
  31. bool hadClients();
  32. private:
  33. QWebSocketServer *m_pWebSocketServer = nullptr;
  34. QList<QWebSocket *> m_clients;
  35. unsigned short m_nPort = 9000;
  36. QString m_strServerName = "server";
  37. };
  38. #endif // WEBSOCKETSERVERBASE_H

服务器基类的源文件:

  1. #include "websocketserverbase.h"
  2. #include<QDebug>
  3. static QString getIdentifier(QWebSocket *peer)
  4. {
  5. return QStringLiteral("%1:%2").arg(peer->peerAddress().toString(),
  6. peer->origin());
  7. }
  8. WebsocketServerBase::WebsocketServerBase(QString serverName, quint16 port, QObject *parent)
  9. : QObject(parent)
  10. ,m_nPort(port)
  11. ,m_strServerName(serverName)
  12. {
  13. }
  14. WebsocketServerBase::~WebsocketServerBase()
  15. {
  16. if(m_pWebSocketServer)
  17. {
  18. m_pWebSocketServer->close();
  19. //m_pWebSocketServer->abort();
  20. m_pWebSocketServer->deleteLater();
  21. }
  22. }
  23. //接收到外部发来的信息,转发给客户端
  24. void WebsocketServerBase::slotSendToAllClients(const QByteArray &data)
  25. {
  26. qDebug() << __FUNCTION__;
  27. for (QWebSocket *pClient : qAsConst(m_clients)) {
  28. qDebug() << "data: " << data;
  29. pClient->sendBinaryMessage(data);
  30. }
  31. }
  32. bool WebsocketServerBase::hadClients()
  33. {
  34. return m_clients.size()>0;
  35. }
  36. void WebsocketServerBase::slotStartServer()
  37. {
  38. if(m_pWebSocketServer)
  39. return;
  40. m_pWebSocketServer = new QWebSocketServer(m_strServerName, QWebSocketServer::NonSecureMode, this);
  41. if (m_pWebSocketServer->listen(QHostAddress::Any, m_nPort))
  42. {
  43. connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &WebsocketServerBase::slotNewConnection);
  44. qDebug() << "WebSocket is start, port:" << m_nPort;
  45. }
  46. }
  47. void WebsocketServerBase::slotNewConnection()
  48. {
  49. auto pSocket = m_pWebSocketServer->nextPendingConnection();
  50. QTextStream(stdout) << getIdentifier(pSocket) << " connected!\n";
  51. qDebug() << "client connected!";
  52. pSocket->setParent(this);
  53. //二进制数据的接收
  54. connect(pSocket, &QWebSocket::binaryMessageReceived, this, &WebsocketServerBase::slotProcessBinaryMessage);
  55. connect(pSocket, &QWebSocket::disconnected, this, &WebsocketServerBase::slotSocketDisconnected);
  56. m_clients << pSocket;
  57. }
  58. void WebsocketServerBase::slotSocketDisconnected()
  59. {
  60. QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
  61. QTextStream(stdout) << getIdentifier(pClient) << " disconnected!\n";
  62. if (pClient)
  63. {
  64. m_clients.removeAll(pClient);
  65. pClient->deleteLater();
  66. }
  67. }
  68. //接收客户端发来的数据,并转发出去
  69. void WebsocketServerBase::slotProcessBinaryMessage(const QByteArray &data)
  70. {
  71. qDebug() << __FUNCTION__ << " data:" << data;
  72. emit sigProcessServerMessage(data);
  73. //test
  74. //slotSendToAllClients(data);
  75. }

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

改造后服务器的头文件:

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

  1. #ifndef READERWEBSOCKETSERVER_H
  2. #define READERWEBSOCKETSERVER_H
  3. #include <QObject>
  4. #include "Singleton.h"
  5. // 回调函数,将websocket的结果抛给上层
  6. typedef void(*recvMsgToSerial)(const QByteArray &byteArray);
  7. class WebsocketServerBase;
  8. class ReaderWebsocketServer : public QObject, public Singleton<ReaderWebsocketServer>
  9. {
  10. Q_OBJECT
  11. friend class Singleton<ReaderWebsocketServer>;
  12. public:
  13. explicit ReaderWebsocketServer(QObject *parent = 0);
  14. virtual ~ReaderWebsocketServer();
  15. public:
  16. // 设置回调函数
  17. void setCallBack(recvMsgToSerial pFunc, void* pUser = NULL);
  18. // 接收串口发来数据,转发给客户端
  19. bool sendData(const QByteArray &byteArray);
  20. signals:
  21. //转发数据给客户端
  22. void sigSendToAllClients(const QByteArray &data);
  23. private slots:
  24. //处理客户端发来的数据,转发给需要的地方
  25. void slotProcessServerMessage(const QByteArray &data);
  26. private:
  27. WebsocketServerBase* m_pWsServer = nullptr;
  28. QThread* m_thdWsServer = nullptr;
  29. void* m_pUser; // 返回回调的对象
  30. recvMsgToSerial m_pRecvMsgToSerial; // 回调
  31. };
  32. #endif // READERWEBSOCKETSERVER_H

改造后服务器的源文件:

  1. #include "readerwebsocketserver.h"
  2. #include <QThread>
  3. #include <cstring>
  4. #include "websocketserverbase.h"
  5. ReaderWebsocketServer::ReaderWebsocketServer(QObject *parent)
  6. : QObject(parent)
  7. {
  8. m_thdWsServer = new QThread();
  9. m_pWsServer = new WebsocketServerBase("reader", 9000);
  10. m_pWsServer->moveToThread(m_thdWsServer);
  11. connect(m_pWsServer, &WebsocketServerBase::sigProcessServerMessage, this, &ReaderWebsocketServer::slotProcessServerMessage);
  12. connect(this, &ReaderWebsocketServer::sigSendToAllClients, m_pWsServer, &WebsocketServerBase::slotSendToAllClients);
  13. connect(m_thdWsServer, &QThread::started, m_pWsServer, &WebsocketServerBase::slotStartServer);
  14. connect(m_thdWsServer, &QThread::finished, m_pWsServer, &WebsocketServerBase::deleteLater);
  15. connect(m_thdWsServer, &QThread::finished, m_thdWsServer, &WebsocketServerBase::deleteLater);
  16. m_thdWsServer->start();
  17. }
  18. ReaderWebsocketServer::~ReaderWebsocketServer()
  19. {
  20. if(m_thdWsServer)
  21. {
  22. m_thdWsServer->quit();
  23. m_thdWsServer->wait();
  24. }
  25. if(m_pWsServer)
  26. {
  27. m_pWsServer->deleteLater();
  28. }
  29. }
  30. void ReaderWebsocketServer::setCallBack(recvMsgToSerial pFunc, void *pUser)
  31. {
  32. if (nullptr != pFunc)
  33. m_pRecvMsgToSerial = pFunc;
  34. if (nullptr != pUser)
  35. m_pUser = pUser;
  36. }
  37. //接收串口发来数据,转发给客户端
  38. bool ReaderWebsocketServer::sendData(const QByteArray &byteArray)
  39. {
  40. bool hadBnode = m_pWsServer->hadClients();
  41. if (hadBnode)
  42. {
  43. emit sigSendToAllClients(byteArray);
  44. }
  45. }
  46. //处理客户端发来的数据,转发给需要的地方
  47. void ReaderWebsocketServer::slotProcessServerMessage(const QByteArray &byteArray)
  48. {
  49. qDebug() << __FUNCTION__ ;
  50. m_pRecvMsgToSerial(byteArray);
  51. }

二、客户端的代码:

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

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

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

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

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

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

(1)客户端基类:

客户端基类的头文件:

  1. /*
  2. * @Description: websocket客户端,用于与中间件通信
  3. */
  4. #pragma once
  5. #include <QObject>
  6. #include <QByteArray>
  7. class QTimer;
  8. class QWebSocket;
  9. class WebSocketBase : public QObject
  10. {
  11. Q_OBJECT
  12. public:
  13. WebSocketBase(QObject *parent = nullptr);
  14. ~WebSocketBase();
  15. void setWebSocketUrl(QString strUrl="");
  16. bool getConnectStatus();
  17. int RecvFrom(QByteArray& byteArray);
  18. signals:
  19. void sigClientBinaryMessageReceived(const QByteArray &byteArray); //借用websocket的信号函数
  20. public slots:
  21. void slotCreateDataRecWS();//创建websocket连接
  22. void slotSendBinaryMessageMessage(const QByteArray &byteArray);
  23. void slotReconnect(); /*-<周期重连函数 */
  24. void slotActiveReconnect();
  25. private slots:
  26. void slotOnConnected(); /*-<socket建立成功后,触发该函数 */
  27. void slotOnBinaryMessageReceived(const QByteArray &byteArray); /*-<收到Sev端的数据时,触发该函数 */
  28. void slotOnDisConnected(); /*-<socket连接断开后,触发该函数 */
  29. private:
  30. QWebSocket *m_pDataRecvWS; /*-<websocket类 */
  31. QTimer *m_pTimer; /*-<周期重连Timer */
  32. QString m_strURL; /*连接URL*/
  33. bool m_bConnectStatus; /*-<websocket连接状态,连接成功:true;断开:false */
  34. QByteArray m_byteArray;
  35. };

客户端基类的源文件:

  1. #include "WebSocketBase.h"
  2. #include <QWebSocket>
  3. #include <QTimer>
  4. #include <QByteArray>
  5. #include <cstring>
  6. WebSocketBase::WebSocketBase(QObject *parent) : QObject(parent)
  7. ,m_pDataRecvWS(nullptr)
  8. ,m_pTimer(nullptr)
  9. ,m_strURL("")
  10. ,m_bConnectStatus(false)
  11. ,m_byteArray("")
  12. {
  13. }
  14. WebSocketBase::~WebSocketBase()
  15. {
  16. m_pTimer->stop();
  17. m_pTimer->deleteLater();
  18. m_pDataRecvWS->abort();
  19. m_pDataRecvWS->deleteLater();
  20. }
  21. void WebSocketBase::setWebSocketUrl(QString strUrl)
  22. {
  23. m_strURL = strUrl;
  24. if(m_strURL.isEmpty())
  25. {
  26. m_strURL = "127.0.0.1";
  27. }
  28. }
  29. bool WebSocketBase::getConnectStatus()
  30. {
  31. return m_bConnectStatus;
  32. }
  33. int WebSocketBase::RecvFrom(QByteArray &byteArray)
  34. {
  35. byteArray = m_byteArray;
  36. m_byteArray.clear();
  37. return byteArray.size();
  38. }
  39. void WebSocketBase::slotCreateDataRecWS()
  40. {
  41. if(nullptr == m_pTimer)
  42. {
  43. m_pTimer = new QTimer();
  44. }
  45. qDebug() << "Server Address" << m_strURL;
  46. if(m_pDataRecvWS == nullptr)
  47. {
  48. m_pDataRecvWS = new QWebSocket();
  49. connect(m_pDataRecvWS, &QWebSocket::disconnected, this, &WebSocketBase::slotOnDisConnected);
  50. connect(m_pDataRecvWS, &QWebSocket::binaryMessageReceived, this, &WebSocketBase::slotOnBinaryMessageReceived);
  51. connect(m_pDataRecvWS, &QWebSocket::connected, this, &WebSocketBase::slotOnConnected);
  52. connect(m_pTimer, &QTimer::timeout, this, &WebSocketBase::slotReconnect);
  53. m_pDataRecvWS->open(QUrl(m_strURL));
  54. }
  55. }
  56. void WebSocketBase::slotSendBinaryMessageMessage(const QByteArray &message)
  57. {
  58. if (m_pDataRecvWS)
  59. m_pDataRecvWS->sendBinaryMessage(message);
  60. }
  61. void WebSocketBase::slotActiveReconnect()
  62. {
  63. qDebug("try to Active Reconnect!!!");
  64. if(m_pDataRecvWS != nullptr)
  65. {
  66. m_bConnectStatus = false;
  67. m_pDataRecvWS->abort();
  68. qDebug("Exec Active Reconnect!");
  69. m_pDataRecvWS->open(QUrl(m_strURL));
  70. }
  71. return;
  72. }
  73. void WebSocketBase::slotReconnect()
  74. {
  75. qDebug() << "try to reconnect:" << m_strURL;
  76. m_pDataRecvWS->abort();
  77. m_pDataRecvWS->open(QUrl(m_strURL));
  78. }
  79. void WebSocketBase::slotOnConnected()
  80. {
  81. qDebug("WebSocketBase websocket is already connect!");
  82. m_bConnectStatus = true;
  83. m_pTimer->stop();
  84. qDebug() << "Address:" << m_strURL;
  85. }
  86. void WebSocketBase::slotOnDisConnected()
  87. {
  88. qDebug() << "Address is disconnected:" << m_strURL;
  89. m_bConnectStatus = false;
  90. m_pTimer->start(3000);/*-<当连接失败时,触发重连计时器,设置计数周期为3秒 */
  91. }
  92. void WebSocketBase::slotOnBinaryMessageReceived(const QByteArray& byteArray)
  93. {
  94. m_byteArray = byteArray;
  95. }

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

改造后客户端头文件:

  1. /*
  2. * @Description: websocket客户端,用于与中间件通信
  3. */
  4. #pragma once
  5. #include <QObject>
  6. #include <QCoreApplication>
  7. #include "Singleton.h"
  8. class WebSocketBase;
  9. class QTimer;
  10. class WsReaderClient : public QObject, public Singleton<WsReaderClient>
  11. {
  12. Q_OBJECT
  13. friend class Singleton<WsReaderClient>;
  14. public:
  15. WsReaderClient(QObject *parent = nullptr);
  16. ~WsReaderClient();
  17. public:
  18. void SendTo(const QByteArray &byteArray);
  19. int RecvFrom(QByteArray& byteArray);
  20. bool getConnectStatus();
  21. signals:
  22. //转发数据给server
  23. void sigSendToServer(const QByteArray &byteArray);
  24. public slots:
  25. //接收服务器数据
  26. void slotRecvServerData(const QByteArray &byteArray);
  27. //发送服务器心跳包
  28. void slotHeartBeatToServer();
  29. private:
  30. void readConfig();
  31. private:
  32. WebSocketBase* m_wsReaderClient;
  33. QThread* m_thdReaderClient;
  34. QTimer *m_pTimerReader;
  35. int m_nHeartBeatTimeOutReader;
  36. QString m_URL = "";
  37. };

改造后客户端源文件:

  1. #include "WsReaderClient.h"
  2. #include <QWebSocket>
  3. #include <QTimer>
  4. #include <QThread>
  5. #include <QByteArray>
  6. #include <cstring>
  7. #include <QSettings>
  8. #include "WebSocketBase.h"
  9. WsReaderClient::WsReaderClient(QObject *parent)
  10. : QObject(parent)
  11. {
  12. readConfig();
  13. m_thdReaderClient = new QThread();
  14. m_wsReaderClient = new WebSocketBase();
  15. m_wsReaderClient->setWebSocketUrl(m_URL);
  16. m_wsReaderClient->moveToThread(m_thdReaderClient);
  17. connect(m_thdReaderClient, &QThread::started, m_wsReaderClient, &WebSocketBase::slotCreateDataRecWS);
  18. connect(this, &WsReaderClient::sigSendToServer, m_wsReaderClient, &WebSocketBase::slotSendBinaryMessageMessage);
  19. //connect(this, &WsReaderClient::sigReconnectServer, m_wsReaderClient, &WebSocketBase::slotActiveReconnect);
  20. connect(m_thdReaderClient, &QThread::finished, m_wsReaderClient, &WebSocketBase::deleteLater);
  21. connect(m_thdReaderClient, &QThread::finished, m_thdReaderClient, &QThread::deleteLater);
  22. m_thdReaderClient->start();
  23. m_pTimerReader = new QTimer(this);
  24. connect(m_pTimerReader, &QTimer::timeout, this, &WsReaderClient::slotHeartBeatToServer);
  25. //m_nHeartBeatTimeOutKeyBoard = 0;
  26. m_pTimerReader->start(10*1000);
  27. }
  28. WsReaderClient::~WsReaderClient()
  29. {
  30. m_pTimerReader->stop();
  31. m_pTimerReader->deleteLater();
  32. if(m_wsReaderClient)
  33. {
  34. delete m_wsReaderClient;
  35. m_wsReaderClient = nullptr;
  36. }
  37. if(m_pTimerReader)
  38. {
  39. delete m_pTimerReader;
  40. m_pTimerReader = nullptr;
  41. }
  42. }
  43. void WsReaderClient::slotHeartBeatToServer()
  44. {
  45. //todo
  46. }
  47. void WsReaderClient::readConfig()
  48. {
  49. // "/mnt/hgfs/SharedFiles/shanxi/Reader/linux_readerTest/bin/libReaderApi.so";
  50. QString appPath = QCoreApplication::applicationDirPath();
  51. qDebug() << "appPath=" << appPath;
  52. QString path = appPath + "/ReaderConfig.ini";
  53. QSettings settings(path, QSettings::IniFormat);
  54. m_URL = settings.value("Communication/ipAddr").toString();
  55. qDebug() << "m_URL=" << m_URL;
  56. }
  57. void WsReaderClient::SendTo(const QByteArray &data)
  58. {
  59. emit sigSendToServer(data);
  60. }
  61. int WsReaderClient::RecvFrom(QByteArray &byteArray)
  62. {
  63. return m_wsReaderClient->RecvFrom(byteArray);
  64. }
  65. bool WsReaderClient::getConnectStatus()
  66. {
  67. return m_wsReaderClient->getConnectStatus();
  68. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/471601
推荐阅读
相关标签
  

闽ICP备14008679号