WTelegram.Client释放后仍占用session文件,重连失败求助
问题诊断与修复方案
核心问题分析
- 递归调用引发多实例竞争:
Login_do异常捕获中递归调用Login_start(),导致多个WTelegram.Client实例创建流程并行执行。即便Dispose当前实例,递归生成的新实例可能在旧实例文件锁未完全释放时就尝试打开session文件,触发占用冲突。 - Dispose后资源释放延迟:
Dispose()调用后,.NET垃圾回收不会立即执行,文件句柄可能仍被系统占用,此时立刻创建新实例会触发文件访问错误。
修复步骤
1. 移除递归调用,统一重试逻辑
将登录重试逻辑集中到外层循环,避免嵌套递归导致的多实例竞争。让Login_do仅负责单次登录尝试,失败后将控制权交还给Login_start处理重试。
2. 确保Dispose后资源彻底释放
Dispose client后,主动触发垃圾回收(此场景下可强制释放文件句柄),或增加短暂延迟让系统完成资源释放。
修改后的代码示例
public async Task Login_start() { while (true) { try { cG.print_inlog($"Connecting & login into Telegram servers..."); // 确保新实例创建前,旧实例已被释放 client?.Dispose(); client = new WTelegram.Client(int.Parse(Config_func("api_id")), Config_func("api_hash")); var loginResult = await Login_do(Config_func("phone_number")); if (loginResult == null) // 登录成功,退出循环 break; // 此处可补充验证码等额外验证逻辑 } catch (Exception ex) { cG.print_inlog($"Login failed: {ex.Message}"); client?.Dispose(); client = null; // 强制触发垃圾回收,确保文件句柄释放 GC.Collect(); GC.WaitForPendingFinalizers(); await Task.Delay(5000); } } } public async Task<string?> Login_do(string loginInfo) { try { cG.print_inlog($"connecting..."); var what = await client.Login(loginInfo); if (what == null) { cG.print_inlog($"We are now connected as {client.User}"); // 复用client执行后续业务操作 var chs = (await client.Messages_GetAllChats()).chats; } return what; } catch (Exception ex) { cG.print_inlog($"Login attempt failed: {ex.Message}"); throw; // 将异常抛回外层,由Login_start统一处理重试 } }
额外优化建议
- 减少Client实例销毁:若仅为网络连接失败,无需完全销毁Client,可尝试
client.Reset(false, true)重置连接状态(保留session),减少文件操作次数,降低锁冲突概率。 - 自定义session路径:创建Client时指定唯一session文件路径,避免默认路径下的文件竞争:
client = new WTelegram.Client(apiId, apiHash, sessionPath: Path.Combine(Path.GetTempPath(), "MyApp_Telegram.session"));
内容的提问来源于stack exchange,提问作者Tecnosoft-dev
相关产品推荐
相关产品推荐

