diff --git a/client/LoginServer.cpp b/client/LoginServer.cpp index 51ff2bc..687d838 100644 --- a/client/LoginServer.cpp +++ b/client/LoginServer.cpp @@ -412,13 +412,13 @@ LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, CONNECT_ADDRESS& conn, const std::string sprintf(cpuInfo, "%dMHz", dwCPUMHz); std::string clientID = cfg.GetStr("settings", "client_id"); if (clientID.empty()) { - // V2 ID 算法:MachineGuid + 归一化路径 - // - 同机同程序路径永远同 ID(不依赖 IP/PCName/OS/CPU 漂移) - // - 局域网多机即便同镜像(sysprep 会让 MachineGuid 各不同)也不撞库 + // V2 ID 算法:MachineGuid + 主机名 + 归一化路径 + // - 主机名兜底区分同镜像克隆机:MachineGuid 相同、路径相同仍能靠主机名区分。 + // - 代价:改名会让 client_id 变化,丢该主机的备注/授权/历史;主机名非硬件唯一,重名仍撞。 // MachineGuid 读取失败的极端情况退化到老算法,保兼容。 std::string machineGuid = GetMachineGuidWindows(); if (!machineGuid.empty()) { - conn.clientID = CalcalateIDv2(machineGuid, NormalizeExePathLower(buf), isAuth); + conn.clientID = CalcalateIDv2(machineGuid + "|" + szPCName, NormalizeExePathLower(buf), isAuth); } else { Mprintf("WARN: MachineGuid 读取失败,回退到老 ID 算法\n"); conn.clientID = CalcalateID({ pubIP, szPCName, LoginInfor.OsVerInfoEx, cpuInfo, buf }); diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index e66148a..b8855cb 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -1748,6 +1748,22 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName return; } if (!ctx->GetClientData(ONLINELIST_IP).IsEmpty()) { + // 诊断:client_id 相同,但主机名/用户名不同 → 很可能是「同镜像克隆机」 + // (MachineGuid 相同 → id 相同,实为不同物理机)。IP 会随 DHCP/公网出口漂移,仅供参考。 + // 写日志供管理员核对,作为后续「重复 id 主动下发新 client_id」的依据。 + CString newUser = v[RES_USERNAME].c_str(); + CString oldUser = ctx->GetAdditionalData(RES_USERNAME); + CString oldName = ctx->GetClientData(ONLINELIST_COMPUTER_NAME); + CString oldIP = ctx->GetClientData(ONLINELIST_IP); + if (strPCName.CompareNoCase(oldName) != 0 || + data[ONLINELIST_IP].CompareNoCase(oldIP) != 0 || + newUser.CompareNoCase(oldUser) != 0) { + Mprintf("WARN: client_id 相同但主机信息不同(疑似克隆机撞 ID)id=%llu\n" + " 新上线: 主机名=%s IP=%s 用户名=%s\n" + " 已在线: 主机名=%s IP=%s 用户名=%s\n", + id, strPCName.GetString(), data[ONLINELIST_IP].GetString(), newUser.GetString(), + oldName.GetString(), oldIP.GetString(), oldUser.GetString()); + } Mprintf("上线消息 - 主机重复上线,暂存替补 [2]: %llu. IP= %s. Path= %s\n", id, data[ONLINELIST_IP], path); // 网络抖动导致客户端用新连接重复上线:这里不立即替换/关闭旧连接, // 否则旧连接被关会触发客户端反复重连抖动(更新前就一直在"替换旧连接")。