From 1a15b87d5bb222446cbaf0d8a690daccc30ce637 Mon Sep 17 00:00:00 2001 From: taynpg Date: Sun, 9 Nov 2025 14:26:39 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E6=8E=A5=E6=94=B6=E7=AB=AF?= =?UTF-8?q?=E6=9C=AA=E6=A3=80=E6=B5=8B=E5=88=B0=E5=8F=91=E9=80=81=E7=AB=AF?= =?UTF-8?q?=E6=96=AD=E8=BF=9E=E7=9A=84=E6=83=85=E5=86=B5=E5=A4=84=E7=90=86?= =?UTF-8?q?=E3=80=82=E5=A4=84=E7=90=86=E4=BC=A0=E8=BE=93=E9=80=80=E5=87=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClientCore/ClientCore.cpp | 34 +++++++++++++++++++--- ClientCore/ClientCore.h | 10 +++++++ ClientCore/FileTrans.cpp | 59 +++++++++++++++++++++++++++++---------- ClientCore/FileTrans.h | 3 ++ Gui/Form/Transform.cpp | 10 +++++-- Gui/Form/Transform.ui | 2 +- Note/version.md | 7 +++-- Protocol/Protocol.h | 1 + README.md | 3 ++ Server/Server.cpp | 2 +- 10 files changed, 105 insertions(+), 26 deletions(-) diff --git a/ClientCore/ClientCore.cpp b/ClientCore/ClientCore.cpp index d77f262..8d6483f 100644 --- a/ClientCore/ClientCore.cpp +++ b/ClientCore/ClientCore.cpp @@ -212,6 +212,7 @@ void ClientCore::UseFrame(QSharedPointer frame) break; } case FBT_SER_MSG_OFFLINE: { + popID(frame->fid); emit sigOffline(frame); break; } @@ -227,6 +228,10 @@ void ClientCore::UseFrame(QSharedPointer frame) emit sigFlowBack(frame); break; } + case FBT_CLI_TRANS_INTERRUPT: { + emit sigTransInterrupt(frame); + break; + } default: qCritical() << QString("未知的帧类型: %1").arg(frame->type); break; @@ -285,6 +290,20 @@ QString ClientCore::GetOwnID() return ownID_; } +void ClientCore::pushID(const QString& id) +{ + QWriteLocker locker(&rwIDLock_); + if (!remoteIDs_.contains(id)) { + remoteIDs_.push_back(id); + } +} + +void ClientCore::popID(const QString& id) +{ + QWriteLocker locker(&rwIDLock_); + remoteIDs_.removeAll(id); +} + SocketWorker::SocketWorker(ClientCore* core, QObject* parent) : QThread(parent), core_(core) { // connect(core_, &ClientCore::sigDisconnect, this, [this]() { @@ -328,10 +347,17 @@ void HeatBeat::run() } ClientCore::syncInvoke(core_, frame); auto rid = core_->GetRemoteID(); - if (rid.isEmpty()) { - continue; + if (!rid.isEmpty()) { + auto frame2 = core_->GetBuffer(info, FBT_SER_MSG_JUDGE_OTHER_ALIVE, rid); + ClientCore::syncInvoke(core_, frame2); + } + + { + QReadLocker loker(&core_->rwIDLock_); + for (auto& id : core_->remoteIDs_) { + auto frame3 = core_->GetBuffer(info, FBT_SER_MSG_JUDGE_OTHER_ALIVE, id); + ClientCore::syncInvoke(core_, frame3); + } } - auto frame2 = core_->GetBuffer(info, FBT_SER_MSG_JUDGE_OTHER_ALIVE, rid); - ClientCore::syncInvoke(core_, frame2); } } \ No newline at end of file diff --git a/ClientCore/ClientCore.h b/ClientCore/ClientCore.h index 581d1cc..fd0dd0d 100644 --- a/ClientCore/ClientCore.h +++ b/ClientCore/ClientCore.h @@ -15,6 +15,7 @@ #include #include #include +#include class ClientCore : public QObject { @@ -81,6 +82,7 @@ signals: void sigMsgAsk(QSharedPointer frame); void sigMsgAnswer(QSharedPointer frame); void sigFlowBack(QSharedPointer frame); + void sigTransInterrupt(QSharedPointer frame); signals: void conSuccess(); @@ -99,10 +101,18 @@ public: void SetRemoteID(const QString& id); QString GetRemoteID(); QString GetOwnID(); + void pushID(const QString& id); + void popID(const QString& id); public: QMutex conMutex_; QString ownID_; + + // 这是被动发送时,对方ID。 + QReadWriteLock rwIDLock_; + QVector remoteIDs_; + + // 这是主动通信时的对方ID。 QString remoteID_; QMutex sockMut_; diff --git a/ClientCore/FileTrans.cpp b/ClientCore/FileTrans.cpp index 2ebd707..7d76f90 100644 --- a/ClientCore/FileTrans.cpp +++ b/ClientCore/FileTrans.cpp @@ -69,8 +69,6 @@ void FileTrans::ReqSendFile(const TransTask& task) void FileTrans::ReqDownFile(const TransTask& task) { - // TODO: check if running... - // start InfoMsg info; info.toPath = task.localPath; @@ -163,6 +161,8 @@ void FileTrans::RegisterSignal() connect(clientCore_, &ClientCore::sigFileInfo, this, [this](QSharedPointer frame) { fbtFileInfo(frame); }); connect(clientCore_, &ClientCore::sigTransFailed, this, [this](QSharedPointer frame) { fbtTransFailed(frame); }); connect(clientCore_, &ClientCore::sigOffline, this, [this](QSharedPointer frame) { fbtInterrupt(frame); }); + connect(clientCore_, &ClientCore::sigTransInterrupt, this, + [this](QSharedPointer frame) { fbtInterrupt(frame); }); } // The other party requests to send, prepare to receive. @@ -221,6 +221,9 @@ void FileTrans::fbtReqSend(QSharedPointer frame) downTask_->file.close(); return; } + + // 需要记录对方的ID,用于心跳检测 + clientCore_->pushID(frame->fid); downTask_->state = TaskState::STATE_RUNNING; } @@ -228,10 +231,6 @@ void FileTrans::fbtReqSend(QSharedPointer frame) void FileTrans::fbtReqDown(QSharedPointer frame) { InfoMsg info = infoUnpack(frame->data); - // judge is same client's same file. - - // judge if file exits etc. - // send auto doTask = QSharedPointer::create(); doTask->file.setFileName(info.fromPath); @@ -261,6 +260,10 @@ void FileTrans::fbtReqDown(QSharedPointer frame) doTask->task.isUpload = true; doTask->task.localPath = info.fromPath; doTask->task.remoteId = frame->fid; + + // 需要记录对方的ID,用于心跳检测 + clientCore_->pushID(frame->fid); + SendFile(doTask); } @@ -347,18 +350,43 @@ void FileTrans::fbtTransFailed(QSharedPointer frame) downTask_->state = TaskState::STATE_FAILED; } -void FileTrans::fbtInterrupt(QSharedPointer frame) +void FileTrans::Interrupt(bool notic) { if (downTask_->state == TaskState::STATE_RUNNING) { qWarning() << QString(tr("传输文件 %1 中断。")).arg(downTask_->file.fileName()); + downTask_->file.close(); + + if (notic) { + InfoMsg info; + info.msg = QString(tr("传输文件 %1 主动中断。")).arg(downTask_->file.fileName()); + auto f = clientCore_->GetBuffer(info, FBT_CLI_TRANS_INTERRUPT, downTask_->task.remoteId); + if (!ClientCore::syncInvoke(clientCore_, f)) { + qCritical() << QString(tr("发送 %1 信息给 %2 失败。")).arg(info.msg).arg(downTask_->task.remoteId); + } + } + downTask_->state = TaskState::STATE_NONE; } if (sendTask_->state == TaskState::STATE_RUNNING) { qWarning() << QString(tr("传输文件 %1 中断。")).arg(sendTask_->file.fileName()); + sendTask_->file.close(); + + InfoMsg info; + info.msg = QString(tr("传输文件 %1 主动中断。")).arg(sendTask_->file.fileName()); + auto f = clientCore_->GetBuffer(info, FBT_CLI_TRANS_INTERRUPT, sendTask_->task.remoteId); + if (!ClientCore::syncInvoke(clientCore_, f)) { + qCritical() << QString(tr("发送 %1 信息给 %2 失败。")).arg(info.msg).arg(sendTask_->task.remoteId); + } + sendTask_->state = TaskState::STATE_NONE; } } +void FileTrans::fbtInterrupt(QSharedPointer frame) +{ + Interrupt(false); +} + void FileTrans::SendFile(const QSharedPointer& task) { auto* sendThread = new SendThread(clientCore_); @@ -387,7 +415,6 @@ void SendThread::run() isSuccess_ = true; delay_ = 0; bool invokeSuccess = false; - qInfo() << tr("开始发送文件:") << task_->file.fileName(); while (!task_->file.atEnd()) { auto frame = QSharedPointer::create(); frame->tid = task_->task.remoteId; @@ -414,12 +441,16 @@ void SendThread::run() // 关键点:这里不调用,无法中途收到别人发的数据。 QCoreApplication::processEvents(); } - qInfo() << tr("结束发送文件:") << task_->file.fileName(); - InfoMsg info; - auto f = cliCore_->GetBuffer(info, FBT_CLI_TRANS_DONE, task_->task.remoteId); - ClientCore::syncInvoke(cliCore_, f); - task_->file.close(); - task_->state = TaskState::STATE_FINISH; + qInfo() << QString(tr("结束发送文件:%1")).arg(task_->file.fileName()); + + // 不是Open表示被别人关闭了,就不发送结束信号了。 + if (task_->file.isOpen()) { + InfoMsg info; + auto f = cliCore_->GetBuffer(info, FBT_CLI_TRANS_DONE, task_->task.remoteId); + ClientCore::syncInvoke(cliCore_, f); + task_->file.close(); + task_->state = TaskState::STATE_FINISH; + } } void SendThread::setTask(const QSharedPointer& task) diff --git a/ClientCore/FileTrans.h b/ClientCore/FileTrans.h index 1efa689..e295bf2 100644 --- a/ClientCore/FileTrans.h +++ b/ClientCore/FileTrans.h @@ -71,6 +71,9 @@ public: qint32 GetSendProgress(); qint32 GetDownProgress(); +public: + void Interrupt(bool notic); + private: void fbtReqSend(QSharedPointer frame); void fbtReqDown(QSharedPointer frame); diff --git a/Gui/Form/Transform.cpp b/Gui/Form/Transform.cpp index b5d8e26..e5e645c 100644 --- a/Gui/Form/Transform.cpp +++ b/Gui/Form/Transform.cpp @@ -34,6 +34,10 @@ void TransForm::SetClientCore(ClientCore* clientCore) { clientCore_ = clientCore; fileTrans_ = new FileTrans(clientCore_); + connect(ui->btnCancel, &QPushButton::clicked, this, [this]() { + fileTrans_->Interrupt(true); + close(); + }); } void TransForm::SetTasks(const QVector& tasks) @@ -68,7 +72,7 @@ void TransForm::startTask() break; } emit sigProgress(progress); - QThread::msleep(2); + QThread::msleep(1); } } else { fileTrans_->ReqDownFile(task); @@ -86,7 +90,7 @@ void TransForm::startTask() break; } emit sigProgress(progress); - QThread::msleep(2); + QThread::msleep(1); } } ++curTaskNum_; @@ -247,4 +251,4 @@ void CheckCondition::run() isAlreadyInter_ = true; emit sigCheckOver(); qInfo() << tr("文件校验结束......"); -} +} \ No newline at end of file diff --git a/Gui/Form/Transform.ui b/Gui/Form/Transform.ui index 9e3c47d..511defc 100644 --- a/Gui/Form/Transform.ui +++ b/Gui/Form/Transform.ui @@ -113,7 +113,7 @@ - 取消退出 + 退出 diff --git a/Note/version.md b/Note/version.md index 5f120fd..32fdd91 100644 --- a/Note/version.md +++ b/Note/version.md @@ -8,14 +8,15 @@ | 序号 | 类型 | 内容 | 说明 | 基于版本 | 完成版本 | | :--: | :--: | ------------------------------------------------------------ | :--: | :------: | :------: | -| 30 | 功能 | 传输界面的取消退出,缺失功能处理。 | | 0.2.2 | | +| 31 | 功能 | Server端buffer大小判断,有过多无效数据则踢出该客户端。 | | 0.2.2 | | +| 30 | 功能 | 传输界面的取消退出,缺失功能处理。 | | 0.2.2 | 0.2.3 | | 29 | 功能 | 根据接收端的速率限制发送端的速度。 | | 0.2.2 | 0.2.3 | | 28 | 变更 | 语言简体中文。 | | 0.2.2 | 0.2.3 | | 27 | 功能 | 传输前检查对方或者自己是否已存在某些文件,提示是否覆盖。 | | 0.2.2 | 0.2.3 | | 26 | 功能 | 最好能保存关闭界面时Splitter和UI的尺寸。 | | 0.2.2 | | | 25 | 功能 | 手动输入的文件夹访问路径保存历史记录,以便后续可能再次使用(10条)。 | | 0.2.2 | | | 24 | 问题 | 发送端如果发送的数据比较大,UI会卡住(功能是正常的)。 | | 0.2.2 | 0.2.3 | -| 23 | 问题 | 作为接收端如果对方断联要处理这个情况。 | | 0.2.2 | | +| 23 | 问题 | 作为接收端如果对方断联要处理这个情况。 | | 0.2.2 | 0.2.3 | | 22 | 功能 | 配置可以切组。 | | 0.2.2 | | | 21 | 功能 | 可以传输文件夹。 | | 0.2.2 | | | 20 | 功能 | 对照传输可以打开本地文件夹。 | | 0.2.2 | 0.2.3 | @@ -36,5 +37,5 @@ | 5 | 问题 | 未设置心跳包,导致超时被Server端踢出。 | 必改 | 0.1 | 0.2 | | 4 | 问题 | 重复链接Server会崩溃。 | | 0.1 | 0.2 | | 3 | 优化 | 首次启动时应当按照当前分辨率进行初始化大小,而不是指定大小。 | | 0.1 | 0.2 | -| 2 | 问题 | 当某个文件传输失败的时候,关闭传输窗口,再次传输显示已经在传输中。 | | 0.1 | | +| 2 | 问题 | 当某个文件传输失败的时候,关闭传输窗口,再次传输显示已经在传输中。 | | 0.1 | 0.2.3 | | 1 | 问题 | Console端显示未注册QSharedPointer\类型 | | 0.1 | 0.2 | diff --git a/Protocol/Protocol.h b/Protocol/Protocol.h index e0c1f53..5b2f6d2 100644 --- a/Protocol/Protocol.h +++ b/Protocol/Protocol.h @@ -42,6 +42,7 @@ enum FrameBufferType : uint16_t { FBT_CLI_FILE_BUFFER, FBT_CLI_TRANS_DONE, FBT_CLI_TRANS_FAILED, + FBT_CLI_TRANS_INTERRUPT, FBT_CLI_FILE_INFO, FBT_MSGINFO_ASK, FBT_MSGINFO_ANSWER diff --git a/README.md b/README.md index 9fc7f01..37ceea6 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ | frelayConsole | 控制台 | 命令行客户端,没有操作功能,一般配合另外一个带GUI的客户端使用。 | | frelayGUI | GUI | GUI客户端。 | +## 注意事项 + +请使用版本一致的三个组件,不可混用。 ## 免责声明与警告 diff --git a/Server/Server.cpp b/Server/Server.cpp index 3df66ed..fab8c28 100644 --- a/Server/Server.cpp +++ b/Server/Server.cpp @@ -210,7 +210,7 @@ void Server::replyRequest(QSharedPointer client, QSharedPointer::create(); rf->type = FBT_SER_MSG_OFFLINE; - rf->fid = id_; + rf->fid = frame->tid; rf->tid = frame->fid; sendData(client->socket, rf); }