Qt開發技術:QWebSocket客戶端、服務端介紹與開發

若該文爲原創文章,未經容許不得轉載
原博主博客地址: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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索