From e40cb4da92b456740b1bec2cbd4b6114d65e519d Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Tue, 27 Jan 2026 19:58:20 +0100 Subject: [PATCH] Fix: #293 Wrong keep-alive time set for IOCPServer --- server/2015Remote/2015RemoteDlg.cpp | 33 +++++++++++++++++++++++++++++ server/2015Remote/2015RemoteDlg.h | 1 + server/2015Remote/IOCPServer.cpp | 2 +- server/2015Remote/Server.h | 12 +++++++++-- server/2015Remote/context.h | 3 +++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 8cdeb7a..cf63afd 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -58,6 +58,7 @@ #define TIMER_CHECK 1 #define TIMER_CLOSEWND 2 #define TIMER_CLEAR_BALLOON 3 +#define TIMER_HEARTBEAT_CHECK 4 #define TODO_NOTICE MessageBoxA("This feature has not been implemented!\nPlease contact: 962914132@qq.com", "提示", MB_ICONINFORMATION); #define TINY_DLL_NAME "TinyRun.dll" #define FRPC_DLL_NAME "Frpc.dll" @@ -1292,6 +1293,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog() #else SetTimer(TIMER_CHECK, max(1, tm) * 60 * 1000, NULL); #endif + SetTimer(TIMER_HEARTBEAT_CHECK, 30 * 1000, NULL); UPDATE_SPLASH(85, "正在启动FRP代理..."); m_hFRPThread = CreateThread(NULL, 0, StartFrpClient, this, NULL, NULL); @@ -1565,10 +1567,39 @@ void CMy2015RemoteDlg::OnTimer(UINT_PTR nIDEvent) nid.szInfoTitle[0] = '\0'; Shell_NotifyIcon(NIM_MODIFY, &nid); } + if (nIDEvent == TIMER_HEARTBEAT_CHECK && m_settings.ReportInterval > 0) { + CheckHeartbeat(); + } CDialogEx::OnTimer(nIDEvent); } +void CMy2015RemoteDlg::CheckHeartbeat() { + CLock lock(m_cs); + auto now = time(0); + int HEARTBEAT_TIMEOUT = max(30, m_settings.ReportInterval * 3); + for (auto it = m_HostList.begin(); it != m_HostList.end(); ) { + context* ContextObject = *it; + if (now - ContextObject->GetLastHeartbeat() > HEARTBEAT_TIMEOUT) { + auto host = ContextObject->GetAdditionalData(RES_CLIENT_PUBIP); + host = host.IsEmpty() ? std::to_string(ContextObject->GetClientID()).c_str() : host; + Mprintf("Client %s[%llu] heartbeat timeout!!! \n", host, ContextObject->GetClientID()); + PostMessageA(WM_SHOWNOTIFY, (WPARAM)new CharMsg("主机掉线"), + (LPARAM)new CharMsg("主机长时间无心跳: " + host)); + it = m_HostList.erase(it); + ContextObject->CancelIO(); + for (int i = 0, n = m_CList_Online.GetItemCount(); i < n; i++) { + auto lParam = m_CList_Online.GetItemData(i); + if (lParam == (LPARAM)ContextObject) { + m_CList_Online.DeleteItem(i); + break; + } + } + } else { + ++it; + } + } +} void CMy2015RemoteDlg::DeletePopupWindow(BOOL bForce) { @@ -2907,6 +2938,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx) BYTE buf[sizeof(HeartbeatACK) + 1] = { CMD_HEARTBEAT_ACK}; memcpy(buf + 1, &ack, sizeof(HeartbeatACK)); ctx->Send2Client(buf, sizeof(buf)); + ctx->SetLastHeartbeat(time(0)); } CLock L(m_cs); @@ -2918,6 +2950,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx) if (hb.Ping > 0) m_CList_Online.SetItemText(i, ONLINELIST_PING, std::to_string(hb.Ping).c_str()); m_CList_Online.SetItemText(i, ONLINELIST_VIDEO, hb.HasSoftware ? "有" : "无"); + id->SetLastHeartbeat(time(0)); return; } } diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 3f842e4..fed8505 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -159,6 +159,7 @@ public: std::string m_selectedGroup; void LoadListData(const std::string& group); void DeletePopupWindow(BOOL bForce = FALSE); + void CheckHeartbeat(); context* FindHost(int port); context* FindHost(uint64_t id); diff --git a/server/2015Remote/IOCPServer.cpp b/server/2015Remote/IOCPServer.cpp index 1c126dd..b769e6c 100644 --- a/server/2015Remote/IOCPServer.cpp +++ b/server/2015Remote/IOCPServer.cpp @@ -700,7 +700,7 @@ void IOCPServer::OnAccept() //设置套接字的选项卡 Set KeepAlive 开启保活机制 SO_KEEPALIVE //保持连接检测对方主机是否崩溃如果2小时内在此套接口的任一方向都没 //有数据交换,TCP就自动给对方 发一个保持存活 - m_ulKeepLiveTime = 3; + m_ulKeepLiveTime = 1000 * 60 * 3; const BOOL bKeepAlive = TRUE; setsockopt(ContextObject->sClientSocket,SOL_SOCKET,SO_KEEPALIVE,(char*)&bKeepAlive,sizeof(bKeepAlive)); diff --git a/server/2015Remote/Server.h b/server/2015Remote/Server.h index c134e80..aac47d1 100644 --- a/server/2015Remote/Server.h +++ b/server/2015Remote/Server.h @@ -339,6 +339,12 @@ public: Zcctx = nullptr; } } + virtual void SetLastHeartbeat(uint64_t time) override { + LastHeartbeatTime = time; + } + virtual uint64_t GetLastHeartbeat() override { + return LastHeartbeatTime; + } CString sClientInfo[ONLINELIST_MAX]; CString additonalInfo[RES_MAX]; SOCKET sClientSocket; @@ -361,7 +367,8 @@ public: ikcpcb* kcp = nullptr; // 新增,指向KCP会话 std::string GroupName; // 分组名称 CLock SendLock; // fix #214 - time_t OnlineTime; // 上线时间 + time_t OnlineTime = 0; // 上线时间 + time_t LastHeartbeatTime = 0; // 最后心跳时间 // 预分配的解压缩缓冲区,避免频繁内存分配 PBYTE DecompressBuffer = nullptr; @@ -483,6 +490,7 @@ public: m_bProxyConnected = FALSE; server = (Server*)svr; OnlineTime = time(0); + LastHeartbeatTime = OnlineTime; } uint64_t GetAliveTime()const { @@ -564,7 +572,7 @@ public: { return ID; } - void CancelIO() + void CancelIO() override { SAFE_CANCELIO(sClientSocket); } diff --git a/server/2015Remote/context.h b/server/2015Remote/context.h index 4a940d2..d68bb2a 100644 --- a/server/2015Remote/context.h +++ b/server/2015Remote/context.h @@ -39,6 +39,9 @@ public: virtual FlagType GetFlagType() const = 0; virtual std::string GetGroupName() const = 0; virtual uint64_t GetAliveTime()const = 0; + virtual void SetLastHeartbeat(uint64_t time) = 0; + virtual uint64_t GetLastHeartbeat() = 0; + virtual void CancelIO() = 0; public: virtual ~context() {} virtual void Destroy() {}