From 8e5ec20cf23b9654ce3603e65e87b164d2144acb Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Tue, 9 Jun 2026 08:37:53 +0200 Subject: [PATCH] Fix: Calculate RTT exclude server side UI queue delay time --- client/KernelManager.cpp | 11 +++++++---- linux/main.cpp | 9 ++++++--- macos/main.mm | 9 ++++++--- server/2015Remote/2015RemoteDlg.cpp | 8 ++++---- server/2015Remote/Server.h | 4 ++++ 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index eb53885..285342f 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -1632,10 +1632,13 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) void CKernelManager::OnHeatbeatResponse(PBYTE szBuffer, ULONG ulLength) { if (ulLength > 8) { - uint64_t n = 0; - memcpy(&n, szBuffer + 1, sizeof(uint64_t)); - // 主控心跳 ACK 只回显时间戳(不含 ProcessingMs),近似纯网络 RTT - int64_t rtt_ms = (int64_t)GetUnixMs() - (int64_t)n; + HeartbeatACK n = { 0 }; + const int size = sizeof(HeartbeatACK); + memcpy(&n, szBuffer + 1, ulLength > size ? size : HeartbeatACK_OldSize); + int64_t total_rtt_ms = (int64_t)GetUnixMs() - (int64_t)n.Time; + int64_t rtt_ms = total_rtt_ms; + if (n.ProcessingMs > 0 && (int64_t)n.ProcessingMs < total_rtt_ms) + rtt_ms = total_rtt_ms - (int64_t)n.ProcessingMs; m_nNetPing.update_from_sample((double)rtt_ms); // 试用版反代理:RTT 入采样窗口。 // 启停由下方根据 m_settings 控制;非试用模式下 RecordSample 内部直接 return。 diff --git a/linux/main.cpp b/linux/main.cpp index 84ca1ff..69a463f 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -398,15 +398,18 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength) HeartbeatACK* ack = (HeartbeatACK*)(szBuffer + 1); uint64_t now = GetUnixMs(); g_lastHeartbeatAckMs.store(now, std::memory_order_relaxed); // 喂应用层 ACK 看门狗 - double rtt_ms = (double)(now - ack->Time); - g_rttEstimator.update_from_sample(rtt_ms); + int64_t total_rtt_ms = (int64_t)now - (int64_t)ack->Time; + int64_t rtt_ms = total_rtt_ms; + if (ack->ProcessingMs > 0 && (int64_t)ack->ProcessingMs < total_rtt_ms) + rtt_ms = total_rtt_ms - (int64_t)ack->ProcessingMs; + g_rttEstimator.update_from_sample((double)rtt_ms); // 心跳节奏太密日志会刷屏;最多 60s 一行 static time_t lastAckLog = 0; time_t now_s = time(nullptr); if (now_s - lastAckLog >= 60) { lastAckLog = now_s; Mprintf("** [%p] Heartbeat ACK: RTT=%.1fms, SRTT=%.1fms ***\n", - user, rtt_ms, g_rttEstimator.srtt * 1000); + user, (double)rtt_ms, g_rttEstimator.srtt * 1000); } } } else if (szBuffer[0] == CMD_MASTERSETTING) { diff --git a/macos/main.mm b/macos/main.mm index 129e2c5..2754be4 100644 --- a/macos/main.mm +++ b/macos/main.mm @@ -750,14 +750,17 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength) if (ulLength >= 1 + sizeof(HeartbeatACK)) { HeartbeatACK* ack = (HeartbeatACK*)(szBuffer + 1); uint64_t now = GetUnixMs(); - double rtt_ms = (double)(now - ack->Time); - g_rttEstimator.update_from_sample(rtt_ms); + int64_t total_rtt_ms = (int64_t)now - (int64_t)ack->Time; + int64_t rtt_ms = total_rtt_ms; + if (ack->ProcessingMs > 0 && (int64_t)ack->ProcessingMs < total_rtt_ms) + rtt_ms = total_rtt_ms - (int64_t)ack->ProcessingMs; + g_rttEstimator.update_from_sample((double)rtt_ms); // Log at most once per minute static uint64_t lastLogTime = 0; if (now - lastLogTime >= 60000) { lastLogTime = now; Mprintf("** [%p] Heartbeat ACK: RTT=%.1fms, SRTT=%.1fms ***\n", - user, rtt_ms, g_rttEstimator.srtt * 1000); + user, (double)rtt_ms, g_rttEstimator.srtt * 1000); } } } else if (szBuffer[0] == CMD_MASTERSETTING) { diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 36521a1..24dd4fe 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -5715,6 +5715,7 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) } case TOKEN_HEARTBEAT: case 137: // 心跳【L】 + ContextObject->HeartbeatRecvMs.store(GetUnixMs(), std::memory_order_relaxed); g_2015RemoteDlg->PostMessageA(WM_UPDATE_ACTIVEWND, 0, (LPARAM)ContextObject); break; case TOKEN_SCREEN_PREVIEW_RSP: { @@ -6488,10 +6489,9 @@ void CMy2015RemoteDlg::SendPendingRenewal(CONTEXT_OBJECT* ctx, const std::string void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx) { - // 记录本心跳的服务端处理开始时间,用于在 ACK 里回报 ProcessingMs。 - // 客户端会用 (now - hb.Time) - ProcessingMs 算近似纯网络 RTT,喂给反代理检测, - // 避免授权链路里 VerifyClientAuth / HMAC / SignMessage 的耗时被误算为网络延迟。 - const uint64_t t_start_ms = GetUnixMs(); + // 用 IOCP 线程记录的收包时刻作为起点,排除 UI 消息队列等待时间, + // 使 ProcessingMs 仅反映真实服务端处理耗时。 + const uint64_t t_start_ms = ctx->HeartbeatRecvMs.load(std::memory_order_relaxed); auto clientID = ctx->GetClientID(); auto host = FindHost(clientID); diff --git a/server/2015Remote/Server.h b/server/2015Remote/Server.h index 89f8127..06af2c4 100644 --- a/server/2015Remote/Server.h +++ b/server/2015Remote/Server.h @@ -392,6 +392,10 @@ public: // 仅作为标记供后续命令处理 / 未来收紧策略使用。 std::atomic m_bAuthenticated{false}; + // 心跳包到达 IOCP 线程的时刻(ms),用于精确计算 ProcessingMs, + // 避免 UI 消息队列等待时间污染服务端耗时统计。 + std::atomic HeartbeatRecvMs{0}; + // 预分配的解压缩缓冲区,避免频繁内存分配 PBYTE DecompressBuffer = nullptr; ULONG DecompressBufferSize = 0;