歡迎技術交流和幫助,提供IT相關服務,索要源碼請聯繫博主QQ: 21497936,若該文爲原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100547400
目錄
enum QWebSocketServer::SslMode
Qt開發筆記:QWebSocket客戶端、服務端介紹與開發
前話
Qt提供的WebSocket功能。
Demo演示
Demo下載地址
包含可執行程序和源碼。
https://download.csdn.net/download/qq21497936/11666770
相關博客
《Qt實用技巧:Qt併發服務器通訊,受同一時刻最大線程數限制(筆者本本同一時刻600多)》
《Qt實用技巧:基於tcp的C/S構架多人聊天程序(在線、離線、離線信息再次登錄後發送等)》
《Qt實用技巧:80顯示超大顯示拼接(十臺服務器,每臺八路攝像頭)方案和Demo》
WebSocket客戶端:QWebSocket
簡介
實現一個TCP套接字,該套接字與WebSocket協議進行通信。
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);
}
歡迎技術交流和幫助,提供IT相關服務,索要源碼請聯繫博主QQ: 21497936,若該文爲原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100547400