若該文爲原創文章,未經容許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100547400web
紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中...(點擊傳送門)安全
Qt開發專欄:開發技術(點擊傳送門)
前話
Qt提供的WebSocket功能。服務器
Demo演示
Demo下載地址
包含可執行程序和源碼。websocket
CSDN: https://download.csdn.net/download/qq21497936/11666770併發
QQ羣:1047134658(點擊「文件」搜索「webSocketDemo」,羣內與博文同步更新全部可開源的源碼模板)socket
相關博客
《Qt實用技巧:Qt併發服務器通信,受同一時刻最大線程數限制(筆者本本同一時刻600多)》tcp
《Qt實用技巧:基於tcp的C/S構架多人聊天程序(在線、離線、離線信息再次登陸後發送等)》函數
《Qt實用技巧:80顯示超大顯示拼接(十臺服務器,每臺八路攝像頭)方案和Demo》工具
WebSocket客戶端:QWebSocket
簡介
實現一個TCP套接字,該套接字與WebSocket協議進行通訊。ui
WebSockets是一種經過單個TCP鏈接提供全雙工通訊通道的Web技術。WebSocket協議在2011年被IETF標準化爲RFC 6455。QWebSocket既可用於客戶端應用程序,也可用於服務器應用程序。
WebSockets的使用參照QTcpServer。
QWebSocket這個類是根據QAbstractSocket建模的。
QWebSocket當前不支持WebSocket擴展和WebSocket子工具。
QWebSocket僅支持WebSocket協議的版本13,如RFC6455所述。
注意:有些代理不理解WebSocket握手過程當中使用的某些HTTP頭。在這種狀況下,不安全的WebSocket鏈接會失敗。緩解此問題的最佳方法是在安全鏈接上使用WebSocket。
警告:要生成掩碼,WebSockets的此實現使用加密不安全的qrand()函數。有關良好遮蔽的重要性的更多信息,請參見林順煌等人的「與本身交談,尋求樂趣和利益」。防範上述文檔中提到的攻擊的最佳措施是經過安全鏈接(wss://)使用QWebSocket。通常來講,請務必當心不要讓第三方腳本訪問應用程序中的QWebSocket。
使用
在工程文件夾中添加:
QT += websockets
包含該類
#include <QWebSocket>
使用時先new一個QWebsocket,而後關聯其connected(),disconnected(),error(),textFrameReceived()(或者textMessageReceived()信號,兩個收到消息的信號都會觸發),發送調用sendTextMessage()函數便可。
關鍵代碼
WebSocketClientManager.h
#ifndef WEBSOCKETCLIENTMANAGER_H #define WEBSOCKETCLIENTMANAGER_H /************************************************************\ * 控件名稱: WebSocket客戶端管理類 * 控件描述: * 1.相似於QTcpServer操做 * 做者:紅模仿 聯繫方式:QQ21497936 * 博客地址:https://blog.csdn.net/qq21497936 * 日期 版本 描述 * 2019年09月04日 v1.0.0 基礎功能 \************************************************************/ #include <QObject> #include <QWebSocket> class WebSocketClientManager : public QObject { Q_OBJECT public: explicit WebSocketClientManager(QObject *parent = nullptr); ~WebSocketClientManager(); public: bool running() const; QString url() const; void setUrl(const QString &url); signals: void signal_connected(); void signal_disconnected(); void signal_sendTextMessageResult(bool result); void signal_sendBinaryMessageResult(bool result); void signal_error(QString errorString); void signal_textFrameReceived(QString frame, bool isLastFrame); void signal_textMessageReceived(QString message); public slots: void slot_start(); void slot_stop(); void slot_connectedTo(QString url); void slot_sendTextMessage(const QString &message); void slot_sendBinaryMessage(const QByteArray &data); protected slots: void slot_connected(); void slot_disconnected(); void slot_error(QAbstractSocket::SocketError error); void slot_textFrameReceived(const QString &frame, bool isLastFrame); void slot_textMessageReceived(const QString &message); private: bool _running; QString _url; bool _connected; QWebSocket *_pWebSocket; }; #endif // WEBSOCKETCLIENTMANAGER_H
WebSocketClientManager.cpp
#include "WebSocketClientManager.h" #include <QDebug> WebSocketClientManager::WebSocketClientManager(QObject *parent) : QObject(parent), _running(false), _pWebSocket(0), _connected(false) { } WebSocketClientManager::~WebSocketClientManager() { if(_pWebSocket != 0) { _pWebSocket->deleteLater(); _pWebSocket = 0; } } bool WebSocketClientManager::running() const { return _running; } void WebSocketClientManager::slot_start() { if(_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << "it's already running..."; return; } if(!_pWebSocket) { _pWebSocket = new QWebSocket(); connect(_pWebSocket, SIGNAL(connected()) , this, SLOT(slot_connected()) ); connect(_pWebSocket, SIGNAL(disconnected()), this, SLOT(slot_disconnected())); connect(_pWebSocket, SIGNAL(error(QAbstractSocket::SocketError)), this , SLOT(slot_error(QAbstractSocket::SocketError))); connect(_pWebSocket, SIGNAL(textFrameReceived(QString,bool)), this , SLOT(slot_textFrameReceived(QString,bool))); connect(_pWebSocket, SIGNAL(textMessageReceived(QString)), this , SLOT(slot_textMessageReceived(QString))); } _running = true; } void WebSocketClientManager::slot_stop() { if(!_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running..."; return; } _running = false; _pWebSocket->close(); } void WebSocketClientManager::slot_connectedTo(QString url) { if(!_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running..."; return; } _pWebSocket->open(QUrl(url)); } void WebSocketClientManager::slot_sendTextMessage(const QString &message) { if(!_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running..."; return; } bool result = true; _pWebSocket->sendTextMessage(message); emit signal_sendTextMessageResult(result); } void WebSocketClientManager::slot_sendBinaryMessage(const QByteArray &data) { if(!_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running..."; return; } bool result = true; _pWebSocket->sendBinaryMessage(data); emit signal_sendBinaryMessageResult(result); } void WebSocketClientManager::slot_connected() { _connected = true; qDebug() << __FILE__ << __LINE__ << "connected"; emit signal_connected(); } void WebSocketClientManager::slot_disconnected() { _connected = false; qDebug() << __FILE__ << __LINE__ << "disconnected"; emit signal_disconnected(); } void WebSocketClientManager::slot_error(QAbstractSocket::SocketError error) { qDebug() << __FILE__ << __LINE__ << (int)error << _pWebSocket->errorString(); emit signal_error(_pWebSocket->errorString()); } void WebSocketClientManager::slot_textFrameReceived(const QString &frame, bool isLastFrame) { emit signal_textFrameReceived(frame, isLastFrame); } void WebSocketClientManager::slot_textMessageReceived(const QString &message) { emit signal_textMessageReceived(message); } QString WebSocketClientManager::url() const { return _url; } void WebSocketClientManager::setUrl(const QString &url) { _url = url; }
WebSocket服務端:QWebSocketServer
簡介
實現基於WebSocket的服務器。
它是以QTcpServer爲模型的,而且行爲相同。使用參照QTcpServer。這個類使得接受傳入的WebSocket鏈接成爲可能。您能夠指定端口或讓QWebSocketServer自動選擇一個端口。您能夠監聽一個特定的地址或機器的全部地址。調用listen()讓服務器監聽傳入的鏈接。
而後,每次客戶端鏈接到服務器時都會發出newConnection()信號。調用nextPendingConnection()將掛起的鏈接接受爲已鏈接的QWebSocket。函數返回指向QabstractSocket::ConnectedState中QWebSocket的指針,可使用該指針與客戶端通訊。
若是發生錯誤,ServerError()返回錯誤類型,而且能夠調用ErrorString()以獲取對所發生狀況的人類可讀描述。
偵聽鏈接時,服務器正在偵聽的地址和端口可用做serverAddress()和serverPort()。
調用close()將使QWebSocketServer中止偵聽傳入的鏈接。
QWebSocket服務器當前不支持WebSocket擴展和WebSocket子工具。
注意:使用自簽名證書時,Firefox bug 594502會阻止firefox鏈接到安全的Websocket服務器。要解決此問題,請首先使用https瀏覽到安全WebSocket服務器。Firefox將指示證書無效。從這裏開始,能夠將證書添加到異常中。在這以後,安全WebSockets鏈接應該能夠工做。
QWebSocketServer僅支持WebSocket協議的版本13,如RFC6455所述。
枚舉
enum QWebSocketServer::SslMode
指示服務器是經過wss(SecureMode)仍是ws(NonSecureMode)運行。
使用
在工程文件夾中添加:
QT += websockets
包含該類
#include <QWebSocketServer>
使用時先new一個QWebSocketServer,傳入服務器名稱和是否使用安全模式(安全模式wss,非安全模式ws),而後關聯其newConnected(),closed(),serverError()。
當收到新的鏈接後,則是轉換爲QWebSocket,而後關聯其connected(),disconnected(),error(),textFrameReceived()(或者textMessageReceived()信號,兩個收到消息的信號都會觸發),發送調用sendTextMessage()函數即。
關鍵代碼
WebSocketServerManager.h
#ifndef WEBSOCKETSERVERMANAGER_H #define WEBSOCKETSERVERMANAGER_H /************************************************************\ * 控件名稱: WebSocket服務器管理類 * 控件描述: * 1.相似於QTcpSocket操做 * 做者:紅模仿 聯繫方式:QQ21497936 * 博客地址:https://blog.csdn.net/qq21497936 * 日期 版本 描述 * 2019年09月04日 v1.0.0 基礎功能 \************************************************************/ #include <QObject> #include <QWebSocketServer> #include <QThread> class WebSocketServerManager : public QObject { Q_OBJECT public: explicit WebSocketServerManager(QString serverName, QWebSocketServer::SslMode secureMode = QWebSocketServer::NonSecureMode, QObject *parent = 0); ~WebSocketServerManager(); public: bool running() const; signals: void signal_conncted(QString ip, qint32 port); void signal_disconncted(QString ip, qint32 port); void signal_sendTextMessageResult(QString ip, quint32 port, bool result); void signal_sendBinaryMessageResult(QString ip, quint32 port, bool result); void signal_error(QString ip, quint32 port, QString errorString); void signal_textFrameReceived(QString ip, quint32 port, QString frame, bool isLastFrame); void signal_textMessageReceived(QString ip, quint32 port,QString message); void signal_close(); public slots: void slot_start(QHostAddress hostAddress = QHostAddress(QHostAddress::Any), qint32 port = 10080); void slot_stop(); void slot_sendData(QString ip, qint32 port, QString message); protected slots: void slot_newConnection(); void slot_serverError(QWebSocketProtocol::CloseCode closeCode); void slot_closed(); protected slots: void slot_disconnected(); void slot_error(QAbstractSocket::SocketError error); void slot_textFrameReceived(const QString &frame, bool isLastFrame); void slot_textMessageReceived(const QString &message); private: QString _serverName; QWebSocketServer::SslMode _sslMode; bool _running; QWebSocketServer *_pWebSocketServer; QHash<QString, QWebSocket*> _hashIpPort2PWebSocket; QHostAddress _listenHostAddress; qint32 _listenPort; }; #endif // WEBSOCKETSERVERMANAGER_H
WebSocketServerManager.cpp
#include "WebSocketServerManager.h" #include <QDebug> #include <QWebSocket> WebSocketServerManager::WebSocketServerManager(QString serverName, QWebSocketServer::SslMode secureMode, QObject *parent) : QObject(parent), _serverName(serverName), _sslMode(secureMode), _running(false), _pWebSocketServer(0) { } WebSocketServerManager::~WebSocketServerManager() { if(_pWebSocketServer != 0) { _pWebSocketServer->deleteLater(); _pWebSocketServer = 0; } } bool WebSocketServerManager::running() const { return _running; } void WebSocketServerManager::slot_start(QHostAddress hostAddress, qint32 port) { if(_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << "it's already running..."; return; } if(!_pWebSocketServer) { _pWebSocketServer = new QWebSocketServer(_serverName, _sslMode, 0); connect(_pWebSocketServer, SIGNAL(newConnection()), this, SLOT(slot_newConnection())); connect(_pWebSocketServer, SIGNAL(closed()), this, SLOT(slot_closed())); connect(_pWebSocketServer, SIGNAL(serverError(QWebSocketProtocol::CloseCode)), this , SLOT(slot_serverError(QWebSocketProtocol::CloseCode))); } _listenHostAddress = hostAddress; _listenPort = port; _pWebSocketServer->listen(_listenHostAddress, _listenPort); _running = true; } void WebSocketServerManager::slot_stop() { if(!_running) { qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running..."; return; } _running = false; _pWebSocketServer->close(); } void WebSocketServerManager::slot_sendData(QString ip, qint32 port, QString message) { QString key = QString("%1-%2").arg(ip).arg(port); if(_hashIpPort2PWebSocket.contains(key)) { _hashIpPort2PWebSocket.value(key)->sendTextMessage(message); } } void WebSocketServerManager::slot_newConnection() { QWebSocket *pWebSocket = _pWebSocketServer->nextPendingConnection(); connect(pWebSocket, SIGNAL(disconnected()), this, SLOT(slot_disconnected())); connect(pWebSocket, SIGNAL(error(QAbstractSocket::SocketError)), this , SLOT(slot_error(QAbstractSocket::SocketError))); // 既會觸發frame接收也會觸發message接收 // connect(pWebSocket, SIGNAL(textFrameReceived(QString,bool)), // this , SLOT(slot_textFrameReceived(QString,bool))); connect(pWebSocket, SIGNAL(textMessageReceived(QString)), this , SLOT(slot_textMessageReceived(QString))); _hashIpPort2PWebSocket.insert(QString("%1-%2").arg(pWebSocket->peerAddress().toString()) .arg(pWebSocket->peerPort()), pWebSocket); qDebug() << __FILE__ << __LINE__ << pWebSocket->peerAddress().toString() << pWebSocket->peerPort(); emit signal_conncted(pWebSocket->peerAddress().toString(), pWebSocket->peerPort()); } void WebSocketServerManager::slot_serverError(QWebSocketProtocol::CloseCode closeCode) { QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender()); if(!pWebSocket) { return; } emit signal_error(pWebSocket->peerAddress().toString(), pWebSocket->peerPort(), _pWebSocketServer->errorString()); } void WebSocketServerManager::slot_closed() { QList<QWebSocket *> _listWebSocket = _hashIpPort2PWebSocket.values(); for(int index = 0; index < _listWebSocket.size(); index++) { _listWebSocket.at(index)->close(); } _hashIpPort2PWebSocket.clear(); emit signal_close(); } void WebSocketServerManager::slot_disconnected() { qDebug() << __FILE__ << __LINE__ << __FUNCTION__; QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender()); if(!pWebSocket) { return; } qDebug() << __FILE__ << __LINE__ << __FUNCTION__; emit signal_disconncted(pWebSocket->peerAddress().toString(), pWebSocket->peerPort()); _hashIpPort2PWebSocket.remove(QString("%1-%2").arg(pWebSocket->peerAddress().toString()) .arg(pWebSocket->peerPort())); } void WebSocketServerManager::slot_error(QAbstractSocket::SocketError error) { QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender()); if(!pWebSocket) { return; } emit signal_error(pWebSocket->peerAddress().toString(), pWebSocket->peerPort(), pWebSocket->errorString()); } void WebSocketServerManager::slot_textFrameReceived(const QString &frame, bool isLastFrame) { QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender()); if(!pWebSocket) { return; } qDebug() << __FILE__ << __LINE__ << frame << isLastFrame; emit signal_textFrameReceived(pWebSocket->peerAddress().toString(), pWebSocket->peerPort(), frame, isLastFrame); } void WebSocketServerManager::slot_textMessageReceived(const QString &message) { QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender()); if(!pWebSocket) { return; } emit signal_textMessageReceived(pWebSocket->peerAddress().toString(), pWebSocket->peerPort(), message); }
若該文爲原創文章,未經容許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100547400
本文同步分享在 博客「紅胖子(AAA紅模仿)」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。