Qt开发技术:QWebSocket客户端、服务端介绍与开发

it2025-11-26  3

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);

}https://blog.csdn.net/qq21497936/article/details/100547400

最新回复(0)