From 9c012b961363e6cef30ada8d2ff125896c709de6 Mon Sep 17 00:00:00 2001 From: taynpg Date: Fri, 20 Jun 2025 14:33:51 +0800 Subject: [PATCH] clientcore: Regardless of whether it is connected, the ClientCore will be uniformly managed by a new thread. --- ClientCore/ClientCore.cpp | 34 +++++++++++-------- ClientCore/ClientCore.h | 28 ++++++++-------- ClientCore/FileTrans.cpp | 18 +++++----- ClientCore/RemoteFile.cpp | 4 +-- Gui/Control/ConnectControl.cpp | 60 ++++++++++++++++++---------------- Gui/Control/ConnectControl.h | 3 +- Gui/frelayGUI.cpp | 45 ++++++++++++------------- 7 files changed, 100 insertions(+), 92 deletions(-) diff --git a/ClientCore/ClientCore.cpp b/ClientCore/ClientCore.cpp index a4ae604..d2152ac 100644 --- a/ClientCore/ClientCore.cpp +++ b/ClientCore/ClientCore.cpp @@ -4,6 +4,11 @@ ClientCore::ClientCore(QObject* parent) : QObject(parent) { +} + +void ClientCore::Instance() +{ + qDebug() << "Instance() thread:" << QThread::currentThread(); socket_ = new QTcpSocket(this); connect(socket_, &QTcpSocket::readyRead, this, &ClientCore::onReadyRead); connect(socket_, &QTcpSocket::disconnected, this, &ClientCore::onDisconnected); @@ -13,6 +18,17 @@ ClientCore::~ClientCore() { } +void ClientCore::DoConnect(const QString& ip, quint16 port) +{ + qDebug() << "doConnect thread:" << QThread::currentThread(); + emit connecting(); + if (!Connect(ip, port)) { + emit conFailed(); + return; + } + emit conSuccess(); +} + bool ClientCore::Connect(const QString& ip, quint16 port) { QMutexLocker locker(&conMutex_); @@ -26,11 +42,13 @@ bool ClientCore::Connect(const QString& ip, quint16 port) return false; } qInfo() << QString(tr("%1:%2 connected success.")).arg(ip).arg(port); + connected_ = true; return true; } void ClientCore::Disconnect() { + connected_ = false; } void ClientCore::onReadyRead() @@ -48,6 +66,7 @@ void ClientCore::onReadyRead() void ClientCore::onDisconnected() { + connected_ = false; qCritical() << QString("client %1 disconnected...").arg(remoteID_); emit sigDisconnect(); } @@ -201,7 +220,6 @@ QString ClientCore::GetOwnID() SocketWorker::SocketWorker(ClientCore* core, QObject* parent) : QThread(parent), core_(core) { connect(core_, &ClientCore::sigDisconnect, this, [this]() { - emit disconnected(); thread()->quit(); }); } @@ -210,19 +228,9 @@ SocketWorker::~SocketWorker() { } -void SocketWorker::SetConnectInfo(const QString& ip, qint16 port) -{ - ip_ = ip; - port_ = port; -} - void SocketWorker::run() { - emit connecting(); - if (!core_->Connect(ip_, port_)) { - emit conFailed(); - return; - } - emit conSuccess(); + qDebug() << "SocketWorker thread:" << QThread::currentThread(); + core_->Instance(); exec(); } diff --git a/ClientCore/ClientCore.h b/ClientCore/ClientCore.h index e403c35..e605d22 100644 --- a/ClientCore/ClientCore.h +++ b/ClientCore/ClientCore.h @@ -27,7 +27,9 @@ public: ~ClientCore(); public: + void Instance(); bool Connect(const QString& ip, quint16 port); + void DoConnect(const QString& ip, quint16 port); void Disconnect(); bool Send(QSharedPointer frame); bool Send(const char* data, qint64 len); @@ -44,7 +46,12 @@ public: f->type = type; return f; } - template static bool asyncInvoke(QObject* context, Callable&& func) + /* + When calling syncInvoke of ClientCore, the ClientCore should not be in the GUI's event loop thread. + In other words, if a ClientCore instance is created in the GUI thread, it should be moved to another thread; + otherwise, it will cause a deadlock and freeze the interface. + */ + template static bool syncInvoke(QObject* context, Callable&& func) { auto promise = QSharedPointer>::create(); QFuture future = promise->future(); @@ -81,6 +88,11 @@ signals: void sigTransFailed(QSharedPointer frame); void sigFileInfo(QSharedPointer frame); +signals: + void conSuccess(); + void connecting(); + void conFailed(); + private: void onReadyRead(); void onDisconnected(); @@ -99,9 +111,10 @@ public: QString remoteID_; QMutex sockMut_; - QTcpSocket* socket_; + QTcpSocket* socket_{}; QByteArray recvBuffer_; + bool connected_{ false }; LocalFile localFile_; }; @@ -113,21 +126,10 @@ public: SocketWorker(ClientCore* core, QObject* parent = nullptr); ~SocketWorker(); -public: - void SetConnectInfo(const QString& ip, qint16 port); - protected: void run() override; -signals: - void conSuccess(); - void connecting(); - void conFailed(); - void disconnected(); - private: - QString ip_; - qint16 port_{}; ClientCore* core_{}; }; diff --git a/ClientCore/FileTrans.cpp b/ClientCore/FileTrans.cpp index a844fd2..2b75a4e 100644 --- a/ClientCore/FileTrans.cpp +++ b/ClientCore/FileTrans.cpp @@ -49,7 +49,7 @@ void FileTrans::ReqSendFile(const TransTask& task) } auto frame = clientCore_->GetBuffer(info, FBT_CLI_REQ_SEND, task.remoteId); - if (!ClientCore::asyncInvoke(clientCore_, [this, frame]() { return clientCore_->Send(frame); })) { + if (!ClientCore::syncInvoke(clientCore_, [this, frame]() { return clientCore_->Send(frame); })) { qCritical() << QString(tr("send req send failed: %1")).arg(info.msg); sendTask_->state = TaskState::STATE_NONE; sendTask_->file.close(); @@ -79,7 +79,7 @@ void FileTrans::ReqDownFile(const TransTask& task) return; } auto frame = clientCore_->GetBuffer(info, FBT_CLI_REQ_DOWN, task.remoteId); - if (!ClientCore::asyncInvoke(clientCore_, [this, frame]() { return clientCore_->Send(frame); })) { + if (!ClientCore::syncInvoke(clientCore_, [this, frame]() { return clientCore_->Send(frame); })) { qCritical() << QString(tr("send req send failed: %1")).arg(info.msg); downTask_->state = TaskState::STATE_NONE; downTask_->file.close(); @@ -154,7 +154,7 @@ void FileTrans::fbtReqSend(QSharedPointer frame) if (downTask_->state == TaskState::STATE_RUNNING) { info.msg = QString(tr("busy...")); auto f = clientCore_->GetBuffer(info, FBT_CLI_CANOT_SEND, frame->fid); - ClientCore::asyncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); }); + ClientCore::syncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); }); return; } @@ -165,7 +165,7 @@ void FileTrans::fbtReqSend(QSharedPointer frame) info.msg = QString(tr("open file failed: %1")).arg(newerPath); qCritical() << info.msg; auto f = clientCore_->GetBuffer(info, FBT_CLI_CANOT_SEND, frame->fid); - if (!ClientCore::asyncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); })) { + if (!ClientCore::syncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); })) { qCritical() << QString(tr("open recv file:%2 failed, and reply %2 failed.")).arg(info.msg, f->fid); downTask_->file.close(); return; @@ -180,7 +180,7 @@ void FileTrans::fbtReqSend(QSharedPointer frame) info.msg = QString(tr("open recv file success: %1")).arg(newerPath); qInfo() << info.msg; auto f = clientCore_->GetBuffer(info, FBT_CLI_CAN_SEND, frame->fid); - if (!ClientCore::asyncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); })) { + if (!ClientCore::syncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); })) { qCritical() << QString(tr("open recv file:%2 success, but reply %2 failed.")).arg(info.msg, frame->fid); downTask_->file.close(); return; @@ -217,7 +217,7 @@ void FileTrans::fbtReqDown(QSharedPointer frame) // reply fileinfo auto f = clientCore_->GetBuffer(info, FBT_CLI_FILE_INFO, frame->fid); - if (!ClientCore::asyncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); })) { + if (!ClientCore::syncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); })) { qCritical() << QString(tr("send file %1 info failed.")).arg(info.fromPath); doTask->file.close(); return; @@ -237,7 +237,7 @@ void FileTrans::fbtTransDone(QSharedPointer frame) info.msg = QString(tr("recv file:%1 success.")).arg(downTask_->file.fileName()); qInfo() << info.msg; auto f = clientCore_->GetBuffer(info, FBT_CLI_CAN_DOWN, frame->fid); - ClientCore::asyncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); }); + ClientCore::syncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); }); return; } qCritical() << QString(tr("recv file:%1 done sigal, but file not opened.")).arg(info.msg); @@ -272,7 +272,7 @@ void FileTrans::fbtFileBuffer(QSharedPointer frame) InfoMsg info; info.msg = downTask_->file.errorString(); auto f = clientCore_->GetBuffer(info, FBT_CLI_TRANS_FAILED, frame->fid); - ClientCore::asyncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); }); + ClientCore::syncInvoke(clientCore_, [this, f]() { return clientCore_->Send(f); }); downTask_->file.close(); } downTask_->tranSize += ws; @@ -372,7 +372,7 @@ void SendThread::run() InfoMsg info; auto f = cliCore_->GetBuffer(info, FBT_CLI_TRANS_DONE, task_->task.remoteId); - ClientCore::asyncInvoke(cliCore_, [this, f]() { return cliCore_->Send(f); }); + ClientCore::syncInvoke(cliCore_, [this, f]() { return cliCore_->Send(f); }); task_->file.close(); task_->state = TaskState::STATE_FINISH; } diff --git a/ClientCore/RemoteFile.cpp b/ClientCore/RemoteFile.cpp index 4efcfb9..5183f59 100644 --- a/ClientCore/RemoteFile.cpp +++ b/ClientCore/RemoteFile.cpp @@ -19,7 +19,7 @@ bool RemoteFile::GetHome() { InfoMsg info; auto frame = cliCore_->GetBuffer(info, FBT_CLI_ASK_HOME, cliCore_->GetRemoteID()); - return ClientCore::asyncInvoke(cliCore_, [this, frame]() { return cliCore_->Send(frame); }); + return ClientCore::syncInvoke(cliCore_, [this, frame]() { return cliCore_->Send(frame); }); } bool RemoteFile::GetDirFile(const QString& dir) @@ -27,5 +27,5 @@ bool RemoteFile::GetDirFile(const QString& dir) InfoMsg info; info.msg = dir; auto frame = cliCore_->GetBuffer(info, FBT_CLI_ASK_DIRFILE, cliCore_->GetRemoteID()); - return ClientCore::asyncInvoke(cliCore_, [this, frame]() { return cliCore_->Send(frame); }); + return ClientCore::syncInvoke(cliCore_, [this, frame]() { return cliCore_->Send(frame); }); } \ No newline at end of file diff --git a/Gui/Control/ConnectControl.cpp b/Gui/Control/ConnectControl.cpp index 6223c48..1f6697f 100644 --- a/Gui/Control/ConnectControl.cpp +++ b/Gui/Control/ConnectControl.cpp @@ -18,10 +18,38 @@ Connecter::~Connecter() delete ui; } -void Connecter::SetClientCore(ClientCore* clientCore) +void Connecter::RunWorker(ClientCore* clientCore) { clientCore_ = clientCore; connect(clientCore_, &ClientCore::sigClients, this, &Connecter::HandleClients); + + sockWorker_ = new SocketWorker(clientCore_, nullptr); + clientCore_->moveToThread(sockWorker_); + + connect(clientCore_, &ClientCore::conSuccess, this, [this]() { + setState(ConnectState::CS_CONNECTED); + qInfo() << QString(tr("Connected.")); + }); + + connect(clientCore_, &ClientCore::conFailed, this, [this]() { + setState(ConnectState::CS_DISCONNECT); + qInfo() << QString(tr("Connect failed.")); + }); + + connect(clientCore_, &ClientCore::connecting, this, [this]() { + setState(ConnectState::CS_CONNECTING); + qInfo() << QString(tr("Connecting...")); + }); + + connect(clientCore_, &ClientCore::sigDisconnect, this, [this]() { + setState(ConnectState::CS_DISCONNECT); + qInfo() << QString(tr("Disconnected.")); + }); + + connect(this, &Connecter::sigDoConnect, clientCore_, &ClientCore::DoConnect); + connect(sockWorker_, &QThread::finished, sockWorker_, &QObject::deleteLater); + + sockWorker_->start(); } void Connecter::SetRemoteCall(const std::function& call) @@ -46,33 +74,7 @@ void Connecter::Connect() FTCommon::msg(this, tr("IP or Port is empty.")); return; } - - sockWorker_ = new SocketWorker(clientCore_, nullptr); - clientCore_->moveToThread(sockWorker_); - - connect(sockWorker_, &SocketWorker::conSuccess, this, [this]() { - setState(ConnectState::CS_CONNECTED); - qInfo() << QString(tr("Connected.")); - }); - - connect(sockWorker_, &SocketWorker::conFailed, this, [this]() { - setState(ConnectState::CS_DISCONNECT); - qInfo() << QString(tr("Connect failed.")); - }); - - connect(sockWorker_, &SocketWorker::connecting, this, [this]() { - setState(ConnectState::CS_CONNECTING); - qInfo() << QString(tr("Connecting...")); - }); - - connect(sockWorker_, &SocketWorker::disconnected, this, [this]() { - setState(ConnectState::CS_DISCONNECT); - qInfo() << QString(tr("Disconnected.")); - }); - - connect(sockWorker_, &QThread::finished, sockWorker_, &QObject::deleteLater); - sockWorker_->SetConnectInfo(ip, port.toInt()); - sockWorker_->start(); + emit sigDoConnect(ip, port.toInt()); } void Connecter::setState(ConnectState cs) @@ -107,7 +109,7 @@ void Connecter::RefreshClient() auto frame = QSharedPointer::create(); frame->data = infoPack(info); frame->type = FBT_SER_MSG_ASKCLIENTS; - auto sendRet = ClientCore::asyncInvoke(clientCore_, [this, frame]() { return clientCore_->Send(frame); }); + auto sendRet = ClientCore::syncInvoke(clientCore_, [this, frame]() { return clientCore_->Send(frame); }); if (!sendRet) { qCritical() << QString(tr("send ask client list failed.")); return; diff --git a/Gui/Control/ConnectControl.h b/Gui/Control/ConnectControl.h index 13b92f5..9fac0dd 100644 --- a/Gui/Control/ConnectControl.h +++ b/Gui/Control/ConnectControl.h @@ -26,12 +26,13 @@ public: ~Connecter(); public: - void SetClientCore(ClientCore* clientCore); + void RunWorker(ClientCore* clientCore); void SetRemoteCall(const std::function& call); void HandleClients(const InfoClientVec& clients); signals: void sendConnect(ConnectState cs); + void sigDoConnect(const QString& ip, quint16 port); private: void InitControl(); diff --git a/Gui/frelayGUI.cpp b/Gui/frelayGUI.cpp index d281fc0..2095da0 100644 --- a/Gui/frelayGUI.cpp +++ b/Gui/frelayGUI.cpp @@ -40,7 +40,7 @@ void frelayGUI::InitControl() transform_->SetClientCore(clientCore_); connecter_ = new Connecter(this); - connecter_->SetClientCore(clientCore_); + connecter_->RunWorker(clientCore_); connecter_->SetRemoteCall([this](const QString& id) { clientCore_->SetRemoteID(id); }); localFile_ = new FileManager(this); @@ -88,30 +88,25 @@ void frelayGUI::ControlLayout() void frelayGUI::ControlMsgHander(QtMsgType type, const QMessageLogContext& context, const QString& msg) { - Q_UNUSED(context); - - //if (!qApp || !qobject_cast(qApp->activeWindow())) { - // return; - //} - - switch (type) { - case QtDebugMsg: - logPrint->Debug(msg); - break; - case QtInfoMsg: - logPrint->Info(msg); - break; - case QtWarningMsg: - logPrint->Warn(msg); - break; - case QtCriticalMsg: - case QtFatalMsg: - logPrint->Error(msg); - break; - default: - logPrint->Error("Unknown QtMsgType type."); - break; - } + QMetaObject::invokeMethod( + qApp, + [type, msg]() { + switch (type) { + case QtDebugMsg: + logPrint->Debug(msg); + break; + case QtInfoMsg: + logPrint->Info(msg); + break; + case QtWarningMsg: + logPrint->Warn(msg); + break; + default: + logPrint->Error(msg); + break; + } + }, + Qt::QueuedConnection); } void frelayGUI::HandleTask(const QVector& tasks)