Conexão WebSockets Com Multi-threads em Qt5
-
QT = core websockets sql
TARGET = milharshow
CONFIG += console
CONFIG -= app_bundleTEMPLATE = app
SOURCES +=
main.cpp
milharshow.cpp
clientthread.cppHEADERS +=
milharshow.h
clientthread.h// main.cpp
#include <QtCore/QCoreApplication>
#include <QDebug>
#include "milharshow.h"int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);MilharShow server(8000);
//Mostra onde está procurando os drivers, libs
foreach (const QString &path, a.libraryPaths()) qDebug() << path;return a.exec();
}// ClientThread.h
#include <QThread>
#include <QWebSocket>class ClientThread : public QThread {
Q_OBJECTpublic:
explicit ClientThread(QWebSocket *socket, QObject parent = nullptr);
~ClientThread() override;
QWebSocket getSocket() const;
void processTextMessage(const QString &message);signals:
void messageReceivedFromClient(const QString &message);protected:
void run() override;private:
QWebSocket *m_socket;
};// ClientThread.cpp
#include "clientthread.h"
ClientThread::ClientThread(QWebSocket *socket, QObject *parent)
: QThread(parent), m_socket(socket) {
connect(m_socket, &QWebSocket::textMessageReceived, this, &ClientThread::processTextMessage);
}ClientThread::~ClientThread() {
m_socket->close();
delete m_socket;
}QWebSocket* ClientThread::getSocket() const {
return m_socket;
}void ClientThread::processTextMessage(const QString &message) {
qDebug() << "Received message in ClientThread:" << message;
// Aqui você pode processar a mensagem recebida pelo cliente
// e possivelmente encaminhá-la para o MilharShow ou para outros clientes
// Por exemplo:
emit messageReceivedFromClient(message);
}void ClientThread::run() {
exec();
}// MilharShow.h
#include "clientthread.h"
#include <QtCore/QObject>
#include <QList>
#include <QtNetwork/QSslError>#include "QtWebSockets/QWebSocketServer"
#include "QtWebSockets/QWebSocket"
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtNetwork/QSslCertificate>
#include <QtNetwork/QSslKey>class MilharShow : public QObject {
Q_OBJECTpublic:
explicit MilharShow(quint16 port, QObject *parent = nullptr);
~MilharShow() override;
QString getIdentifier(QWebSocket *peer) const;private slots:
void onNewConnection();
void processMessage(const QString &message);
void removeClient(ClientThread *client);
void onSslErrors(const QList<QSslError> &);private:
QWebSocketServer *m_pWebSocketServer;
QList<ClientThread *> m_clients;
};// MilharShow.cpp
#include "milharshow.h"
#include <QTextStream> // ou <QtCore/QTextStream> dependendo da organização do seu projetoMilharShow::MilharShow(quint16 port, QObject *parent)
: QObject(parent), m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Chat Server"),
QWebSocketServer::SecureMode, this)) {
QSslConfiguration sslConfiguration;
//QFile certFile(QStringLiteral("/usr/qt-projetos/milharshow/milharshow.cert"));
//QFile keyFile(QStringLiteral("/usr/qt-projetos/milharshow/milharshow.key"));
QFile certFile(QStringLiteral("/etc/letsencrypt/live/jrprogrammer.com.br/fullchain.pem"));
QFile keyFile(QStringLiteral("/etc/letsencrypt/live/jrprogrammer.com.br/privkey.pem"));
certFile.open(QIODevice::ReadOnly);
keyFile.open(QIODevice::ReadOnly);
QSslCertificate certificate(&certFile, QSsl::Pem);
QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
certFile.close();
keyFile.close();
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
sslConfiguration.setLocalCertificate(certificate);
sslConfiguration.setPrivateKey(sslKey);
sslConfiguration.setProtocol (QSsl::TlsV1SslV3);
m_pWebSocketServer->setSslConfiguration(sslConfiguration);if (m_pWebSocketServer->listen(QHostAddress::Any, port)) {
connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &MilharShow::onNewConnection);
connect(m_pWebSocketServer, &QWebSocketServer::sslErrors, this, &MilharShow::onSslErrors);
}
}MilharShow::~MilharShow() {
m_pWebSocketServer->close();// Como os objetos QWebSocket são gerenciados pelas threads,
// não excluímos explicitamente os sockets aqui.
// Em vez disso, encerramos as threads para garantir que elas liberem recursos.
for (ClientThread *client : qAsConst(m_clients)) {
client->quit(); // Solicita a finalização da thread
client->wait(); // Aguarda até que a thread seja encerrada
}
}QString MilharShow::getIdentifier(QWebSocket *peer) const {
return QStringLiteral("%1:%2").arg(peer->peerAddress().toString(),
QString::number(peer->peerPort()));
}void MilharShow::onNewConnection() {
auto pSocket = m_pWebSocketServer->nextPendingConnection();
QTextStream(stdout) << getIdentifier(pSocket) << " connected!\n";ClientThread *clientThread = new ClientThread(pSocket);
connect(clientThread, &ClientThread::finished, clientThread, &ClientThread::deleteLater);
connect(clientThread, &ClientThread::messageReceivedFromClient, this, &MilharShow::processMessage);
connect(clientThread, &ClientThread::finished, this, [this, clientThread] { removeClient(clientThread); });m_clients.append(clientThread);
clientThread->start();
}void MilharShow::processMessage(const QString &message) {
QWebSocket *pSender = qobject_cast<QWebSocket *>(sender());
if (!pSender) {
qDebug() << "Vai retornar!" << pSender ;
//return;
}QByteArray byteArray = message.toUtf8();
// Adicione a saída de debug para verificar se a função é chamada
qDebug() << "Received message:" << message;for (ClientThread clientThread : qAsConst(m_clients)) {
QWebSocket socket = clientThread->getSocket();
if (socket && socket->isValid() && socket != pSender) {
socket->sendTextMessage(QString::fromUtf8(byteArray));
}
}
}void MilharShow::removeClient(ClientThread *client) {
m_clients.removeAll(client);
}void MilharShow::onSslErrors(const QList<QSslError> &errors) {
qDebug() << "SSL errors occurred:";
for (const QSslError &error : errors) {
qDebug() << "Error: " << error.errorString();
}
}Só tem uma questão neste exemplo:
void MilharShow::processMessage(const QString &message) {
QWebSocket *pSender = qobject_cast<QWebSocket *>(sender());
if (!pSender) {
qDebug() << "Vai retornar!" << pSender ;
//return;
}
Nestes trecho de código, Sender() está chegando com valor igual a NULO. Mas como podem observar, comentei a saída de //RETURN; Com esta atitude o sistema funciona e vemos as mensagens fluirem. Mas tem uma questão, as mensagens enviadas que deveriam ser passadas somente para os outros clientes, está também, sendo emitida para o próprio cliente que mandou a mensagem. É só isso mesmo que falta para ficar bem legal. Como alguns vai perceber, o código original desse projeeto foi o exemplo simpleChat do Qt5. Se alguém poder ajudar a resolver no pouquinho que falta, agradeço muito! -