diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs index 5fe1008..860944d 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs @@ -999,6 +999,7 @@ namespace JoyD.Windows.CS.Toprie try { + lock (_lockObject) { _isTemperatureReceivingPaused = true; @@ -1030,6 +1031,10 @@ namespace JoyD.Windows.CS.Toprie try { + // 记录调用堆栈,帮助定位问题 + string callStack = Environment.StackTrace; + Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ResumeTemperatureDataReceiving() - 调用堆栈:\n{callStack}"); + lock (_lockObject) { _isTemperatureReceivingPaused = false; @@ -1165,106 +1170,74 @@ namespace JoyD.Windows.CS.Toprie byte[] buffer = new byte[65536]; // 缓冲区大小 // 定义常量 - const int RECEIVE_TIMEOUT = 30000; // 增加到30秒,减少因超时导致的断开 - const int MEDIUM_SLEEP_MS = 50; - const int LONG_SLEEP_MS = 2000; // 增加重连等待时间 - const int ERROR_SLEEP_MS = 1000; // 增加异常恢复等待时间 + const int RECEIVE_TIMEOUT = 30000; // 30秒超时 + const int SLEEP_MS = 1000; // 标准等待时间 + const int CONNECTION_CHECK_INTERVAL_MS = 5000; // 连接检查间隔5秒 + const int LONG_SLEEP_MS = 5000; // 长等待时间 + const int ERROR_SLEEP_MS = 3000; // 错误后等待时间 try { // 主循环,持续执行直到收到停止信号 - while (true) + while (!ShouldStop()) { - // 检查停止信号和对象是否已释放 - bool shouldStop = false; - lock (_lockObject) - { - shouldStop = (_stopTemperatureEvent != null && _stopTemperatureEvent.WaitOne(0)) || _isDisposed; - } - - if (shouldStop) - { - Log("接收到停止信号或对象已释放,准备退出温度数据接收循环"); - break; - } // 获取当前状态和配置 bool isPaused = false; string deviceIp = null; - int temperaturePort = 0; + int temperaturePort = TEMPERATURE_TCP_PORT; lock (_lockObject) { isPaused = _isTemperatureReceivingPaused; deviceIp = _deviceIp; - temperaturePort = TEMPERATURE_TCP_PORT; } - // 连接管理:当连接不存在、已断开或检测到连接不可用时创建新连接 - if (localTcpClient == null || !IsTcpClientConnected(localTcpClient) || localStream == null) + // 如果连接不存在或已断开,创建新连接 + if (localTcpClient == null || !IsTcpClientConnected(localTcpClient)) { + // 如果处于暂停状态,则Sleep 1秒后继续执行 + if (isPaused) + { + Thread.Sleep(SLEEP_MS); + continue; + } + + // 否则创建一个新的连接实例 + Log("创建新的温度数据TCP连接..."); + // 清理之前可能存在的连接资源 - try - { - if (localStream != null) - { - localStream.Close(); - localStream = null; - } - if (localTcpClient != null) - { - localTcpClient.Close(); - localTcpClient = null; - } - } - catch (Exception ex) - { - Log($"关闭旧连接异常: {ex.Message}"); - } + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); try { - // 只有在未暂停状态下才创建连接 - if (!isPaused) + // 创建TCP客户端并连接 + localTcpClient = new TcpClient { - Log("创建新的温度数据TCP连接..."); - - // 创建TCP客户端并连接 - localTcpClient = new TcpClient - { - ReceiveTimeout = RECEIVE_TIMEOUT, - SendTimeout = RECEIVE_TIMEOUT - }; - // 设置接收缓冲区大小 - localTcpClient.ReceiveBufferSize = 65536; // 64KB - - Log($"正在连接到温度数据端口 {temperaturePort}..."); - localTcpClient.Connect(deviceIp, temperaturePort); - Log("温度数据TCP连接成功"); - - // 获取网络流 - localStream = localTcpClient.GetStream(); - localStream.ReadTimeout = RECEIVE_TIMEOUT; - - // 更新状态标志 - lock (_lockObject) - { - _isReceivingTemperatureData = true; - } - - // 发送开始温度数据传输的命令 - byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n"); - localStream.Write(startCommand, 0, startCommand.Length); - localStream.Flush(); - Log("已发送开始温度数据传输命令"); - } - else + ReceiveTimeout = RECEIVE_TIMEOUT, + SendTimeout = RECEIVE_TIMEOUT, + ReceiveBufferSize = 65536 // 64KB + }; + + Log($"正在连接到温度数据端口 {temperaturePort}..."); + localTcpClient.Connect(deviceIp, temperaturePort); + Log("温度数据TCP连接成功"); + + // 获取网络流 + localStream = localTcpClient.GetStream(); + localStream.ReadTimeout = RECEIVE_TIMEOUT; + + // 更新状态标志 + lock (_lockObject) { - // 暂停状态下短暂等待后重试 - Log("处于暂停状态,等待后重试连接"); - Thread.Sleep(LONG_SLEEP_MS); - continue; + _isReceivingTemperatureData = true; } + + // 发送开始温度数据传输的命令 + byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n"); + localStream.Write(startCommand, 0, startCommand.Length); + localStream.Flush(); + Log("已发送开始温度数据传输命令"); } catch (Exception ex) { @@ -1296,41 +1269,77 @@ namespace JoyD.Windows.CS.Toprie // 记录上次心跳时间和上次接收数据时间 DateTime lastHeartbeatTime = DateTime.Now; DateTime lastReceiveTime = DateTime.Now; + DateTime lastConnectionCheckTime = DateTime.Now; + DateTime lastPausedLogTime = DateTime.MinValue; + const int PAUSED_LOG_INTERVAL_MS = 30000; // 暂停状态日志间隔30秒 + + // 记录上次暂停状态,用于检测状态变化 + bool lastPaused = false; + + // 初始化lastPaused为当前状态 + lock (_lockObject) + { + lastPaused = _isTemperatureReceivingPaused; + isPaused = lastPaused; + } // 持续读取温度数据流 while (localTcpClient != null && localTcpClient.Connected) { - // 检查是否暂停 - lock (_lockObject) + // 每次循环开始时检查是否收到停止信号 + if (ShouldStop()) { - isPaused = _isTemperatureReceivingPaused; + Log("TCP连接循环中检测到停止信号,准备退出循环"); + break; } + + // 检测暂停状态是否发生变化 + bool currentPaused = IsTemperatureReceivingPaused(); + if (currentPaused != lastPaused) + { + if (currentPaused) + { + Log("温度接收暂停状态变化: 从运行中变为暂停"); + } + else + { + Log("温度接收暂停状态变化: 从暂停变为运行中"); + } + // 更新lastPaused为当前状态 + lastPaused = currentPaused; + } + // 更新isPaused为当前状态供后续使用 + isPaused = currentPaused; if (isPaused) { - Log("温度接收已暂停,等待恢复"); - Thread.Sleep(MEDIUM_SLEEP_MS); - // 在暂停状态下,仍然需要定期检查连接是否有效 - if (localTcpClient != null && !IsTcpClientConnected(localTcpClient)) + // 减少暂停状态下的日志记录频率,避免日志过于冗长 + DateTime currentTime = DateTime.Now; + if ((currentTime - lastPausedLogTime).TotalMilliseconds > PAUSED_LOG_INTERVAL_MS) { - Log("暂停状态下检测到连接已断开,将在恢复时重建连接"); - try + Log("温度接收已暂停,等待恢复"); + lastPausedLogTime = currentTime; + } + + // 在暂停状态的Sleep前检查是否收到停止信号 + if (ShouldStop()) + { + Log("暂停状态下检测到停止信号,准备退出循环"); + break; + } + + // 根据规范,暂停时Sleep 1秒 + Thread.Sleep(1000); + + // 在暂停状态下,降低连接检查频率 + if ((currentTime - lastConnectionCheckTime).TotalMilliseconds > CONNECTION_CHECK_INTERVAL_MS) + { + if (localTcpClient != null && !IsTcpClientConnected(localTcpClient)) { - if (localStream != null) - { - localStream.Close(); - localStream = null; - } - if (localTcpClient != null) - { - localTcpClient.Close(); - localTcpClient = null; - } - } - catch (Exception ex) - { - Log($"关闭无效连接时发生异常: {ex.Message}"); + Log("暂停状态下检测到连接已断开,将在恢复时重建连接"); + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); } + lastConnectionCheckTime = currentTime; } continue; } @@ -1340,23 +1349,7 @@ namespace JoyD.Windows.CS.Toprie if (localTcpClient != null && !IsTcpClientConnected(localTcpClient)) { Log("恢复接收时检测到连接无效,需要重建连接"); - try - { - if (localStream != null) - { - localStream.Close(); - localStream = null; - } - if (localTcpClient != null) - { - localTcpClient.Close(); - localTcpClient = null; - } - } - catch (Exception ex) - { - Log($"关闭无效连接时发生异常: {ex.Message}"); - } + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); // 跳出内层循环,回到外层循环重新建立连接 break; } @@ -1368,7 +1361,15 @@ namespace JoyD.Windows.CS.Toprie byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n"); localStream.Write(startCommand, 0, startCommand.Length); localStream.Flush(); - Log("从暂停状态恢复,重新发送开始温度数据传输命令"); + + // 只有在从暂停状态恢复时(状态从true变为false的瞬间)才记录日志 + lock (_lockObject) + { + if (lastPaused && !_isTemperatureReceivingPaused) + { + Log("从暂停状态恢复,重新发送开始温度数据传输命令"); + } + } } catch (Exception ex) { @@ -1398,27 +1399,16 @@ namespace JoyD.Windows.CS.Toprie // 使用非阻塞方式检查是否有数据可读 // 先检查连接是否仍然有效 - if (localTcpClient != null && !IsTcpClientConnected(localTcpClient)) + DateTime now = DateTime.Now; + if ((now - lastConnectionCheckTime).TotalMilliseconds > CONNECTION_CHECK_INTERVAL_MS) { - Log("检测到连接已断开,准备重建连接"); - try + if (localTcpClient != null && !IsTcpClientConnected(localTcpClient)) { - if (localStream != null) - { - localStream.Close(); - localStream = null; - } - if (localTcpClient != null) - { - localTcpClient.Close(); - localTcpClient = null; - } + Log("检测到连接已断开,准备重建连接"); + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); + continue; } - catch (Exception ex) - { - Log($"关闭断开的连接时发生异常: {ex.Message}"); - } - continue; + lastConnectionCheckTime = now; } if (localStream.DataAvailable) @@ -1434,6 +1424,8 @@ namespace JoyD.Windows.CS.Toprie if (isPaused) { Log("处于暂停状态,数据已接收但丢弃"); + // 根据规范,暂停时Sleep 1秒 + Thread.Sleep(1000); } else { @@ -1441,7 +1433,15 @@ namespace JoyD.Windows.CS.Toprie Array.Copy(buffer, receivedBytes, bytesRead); // 同步接收并处理数据 temperatureDataAccumulator.Add(receivedBytes); + // 记录处理开始时间 + System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); + stopwatch.Start(); + ProcessReceivedTemperatureData(temperatureDataAccumulator); + + // 停止计时并记录处理时间 + stopwatch.Stop(); + Log($"处理温度数据耗时: {stopwatch.ElapsedMilliseconds}ms"); } } else if (bytesRead == 0) @@ -1456,23 +1456,7 @@ namespace JoyD.Windows.CS.Toprie } // 清理连接资源 - try - { - if (localStream != null) - { - localStream.Close(); - localStream = null; - } - if (localTcpClient != null) - { - localTcpClient.Close(); - localTcpClient = null; - } - } - catch { } - - localStream = null; - localTcpClient = null; + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); continue; } } @@ -1481,7 +1465,7 @@ namespace JoyD.Windows.CS.Toprie } catch (Exception ex) { - Log($"接收数据异常: {ex.Message}"); + Log($"接收数据异常: {ex.Message}, 堆栈: {ex.StackTrace}"); // 更新状态标志 lock (_lockObject) @@ -1490,93 +1474,220 @@ namespace JoyD.Windows.CS.Toprie } // 清理连接资源 - try - { - localStream.Close(); - localTcpClient.Close(); - } - catch {} - - localStream = null; - localTcpClient = null; + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); // 异常后等待一段时间再重试 Thread.Sleep(ERROR_SLEEP_MS); } } - else - { - // 没有有效连接,短暂休眠 - Thread.Sleep(MEDIUM_SLEEP_MS); - } } } - catch (Exception ex) - { - Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 严重异常: {ex.Message}"); - } finally { Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 执行完成"); - - // 确保状态正确更新 - lock (_lockObject) - { - _isReceivingTemperatureData = false; - } - - // 清理资源 - try - { - if (localStream != null) - { - localStream.Close(); - localStream = null; - } - } - catch {} - - try - { - if (localTcpClient != null) - { - localTcpClient.Close(); - localTcpClient = null; - } - } - catch {} - - Log("温度数据接收线程已结束,重置相关状态"); + + // 确保状态正确更新 + lock (_lockObject) + { + _isReceivingTemperatureData = false; } + + // 清理资源 + CleanupConnectionResources(localStream, localTcpClient, out localStream, out localTcpClient); + + Log("温度数据接收线程已结束,重置相关状态"); + } } + /// + /// 检查是否应该停止接收温度数据 + /// + private bool ShouldStop() + { + lock (_lockObject) + { + return (_stopTemperatureEvent != null && _stopTemperatureEvent.WaitOne(0)) || _isDisposed; + } + } + + /// + /// 清理连接资源 + /// + private void CleanupConnectionResources(ref NetworkStream stream, ref TcpClient client) + { + try + { + if (stream != null) + { + stream.Close(); + stream = null; + } + } + catch (Exception ex) + { + Log($"关闭网络流异常: {ex.Message}"); + } + + try + { + if (client != null) + { + client.Close(); + client = null; + } + } + catch (Exception ex) + { + Log($"关闭TCP客户端异常: {ex.Message}"); + } + } + + /// + /// 检查温度接收是否处于暂停状态 + /// + private bool IsTemperatureReceivingPaused() + { + lock (_lockObject) + { + return _isTemperatureReceivingPaused; + } + } + + /// + /// 设置温度接收状态标志 + /// + private void SetReceivingState(bool isReceiving) + { + lock (_lockObject) + { + _isReceivingTemperatureData = isReceiving; + } + } + /// /// 处理接收到的温度数据 /// - /// 累积的温度数据 + /// 累积的温度数据包列表 private void ProcessReceivedTemperatureData(List dataAccumulator) { - //根据TemperatureData类的要求,每个温度帧包含9字节头部 + 温度数据 - // 根据注释,设备实际提供的数据分辨率应为256x192,最终映射到512x384显示 - const int HEADER_SIZE = 9; // 9字节头部("+TEMP"+数据长度) + // 头部标识 + const string HEADER_MARKER = "+TEMP"; const int WIDTH = 256; const int HEIGHT = 192; - const int TEMPERATURE_DATA_FRAME_SIZE = HEADER_SIZE + WIDTH * HEIGHT * 2; // 9字节头部 + 每个温度值2字节 + const int HEADER_SIZE = 9; // 9字节头部("+TEMP"+数据长度) try { - Log($"开始处理温度数据,当前累积数据量: {dataAccumulator.Count} 字节,所需帧大小: {TEMPERATURE_DATA_FRAME_SIZE} 字节"); - - // 检查是否有足够的数据构成完整的温度数据帧 - while (dataAccumulator.Count >= TEMPERATURE_DATA_FRAME_SIZE) + Log($"开始处理温度数据,当前累积数据包数量: {dataAccumulator.Count}"); + // 开始循环处理列表 + while (dataAccumulator.Count > 0) { - Log($"找到完整的温度数据帧,开始处理"); + // 从列表中读取第一个数组 + byte[] currentArray = dataAccumulator[0]; + Log($"检查第一个数组,长度: {currentArray.Length} 字节"); - // 提取一帧温度数据 - byte[] temperatureFrame = dataAccumulator.GetRange(0, TEMPERATURE_DATA_FRAME_SIZE).ToArray(); - dataAccumulator.RemoveRange(0, TEMPERATURE_DATA_FRAME_SIZE); + // 查看是否有头信息 + int headerIndex = FindHeader(currentArray, HEADER_MARKER); + + if (headerIndex == -1) + { + // 如果没有头信息,将数组从列表中移除 + Log("未在数组中找到头部信息,移除该数组"); + dataAccumulator.RemoveAt(0); + // 跳转到循环开始,检查列表是否为空 + continue; + } - Log($"提取温度数据帧完成,剩余累积数据量: {dataAccumulator.Count} 字节"); + // 如果头部不在数组的开始位置,需要移除头部之前的无效数据 + if (headerIndex > 0) + { + Log($"头部不在数组开始位置,移除前 {headerIndex} 个无效字节"); + byte[] newArray = new byte[currentArray.Length - headerIndex]; + Array.Copy(currentArray, headerIndex, newArray, 0, newArray.Length); + dataAccumulator[0] = newArray; + currentArray = newArray; + } + + // 查看头信息中数据长度信息 + // 确保数组至少包含完整的头部 + if (currentArray.Length < HEADER_SIZE) + { + Log("数组长度不足头部大小,退出循环"); + break; + } + + // 从头部解析数据长度 + int dataLength = CalculateDataLength(currentArray); + int totalFrameSize = HEADER_SIZE + dataLength; + + // 检查数组中是否有足够的数据长度 + while (currentArray.Length < totalFrameSize) + { + // 如果没有足够的数据长度,看列表中是否有下一个数组 + if (dataAccumulator.Count <= 1) + { + // 如果没有,则退出循环 + Log("数据长度不足,且没有更多数组可以合并,退出循环"); + break; + } + else + { + // 否则将下一个数组合并到当前数组中尾部 + Log("数据长度不足,合并下一个数组到当前数组尾部"); + byte[] nextArray = dataAccumulator[1]; + byte[] mergedArray = new byte[currentArray.Length + nextArray.Length]; + Array.Copy(currentArray, 0, mergedArray, 0, currentArray.Length); + Array.Copy(nextArray, 0, mergedArray, currentArray.Length, nextArray.Length); + + // 更新当前数组和列表 + dataAccumulator[0] = mergedArray; + dataAccumulator.RemoveAt(1); + currentArray = mergedArray; + Log($"合并后数组长度: {currentArray.Length} 字节"); + } + } + + // 检查数据是否足够(可能因为没有更多数组可以合并而不足) + if (currentArray.Length < totalFrameSize) + { + Log("数据长度仍不足,退出循环等待更多数据"); + break; + } + + // 检查数据长度范围内是否又出现了头信息 + int nextHeaderIndex = FindHeader(currentArray, HEADER_MARKER, HEADER_SIZE, totalFrameSize); + if (nextHeaderIndex != -1) + { + // 如果有,则将数组中第二个头信息之前的数据移除 + Log($"在数据长度范围内发现另一个头信息,索引位置: {nextHeaderIndex},移除前面的数据"); + byte[] newArray = new byte[currentArray.Length - nextHeaderIndex]; + Array.Copy(currentArray, nextHeaderIndex, newArray, 0, newArray.Length); + dataAccumulator[0] = newArray; + // 跳转到检查头信息的步骤 + continue; + } + + // 如果没有重复头信息,则将数据长度范围内的数据从数组取出进行处理 + Log($"数据有效,提取完整帧数据,长度: {totalFrameSize} 字节"); + byte[] temperatureFrame = new byte[totalFrameSize]; + Array.Copy(currentArray, 0, temperatureFrame, 0, totalFrameSize); + + // 保留剩余部分到数组中 + if (currentArray.Length > totalFrameSize) + { + Log($"保留剩余数据,长度: {currentArray.Length - totalFrameSize} 字节"); + byte[] remainingBytes = new byte[currentArray.Length - totalFrameSize]; + Array.Copy(currentArray, totalFrameSize, remainingBytes, 0, remainingBytes.Length); + dataAccumulator[0] = remainingBytes; + } + else + { + // 如果没有剩余数据,移除当前数组 + dataAccumulator.RemoveAt(0); + } + + // 处理提取出的温度数据帧 + Log($"成功提取完整温度数据帧,长度: {temperatureFrame.Length} 字节"); // 获取温度补偿值 float compensationValue = GetTemperatureCompensationValue(); @@ -1591,7 +1702,7 @@ namespace JoyD.Windows.CS.Toprie Log($"温度数据接收事件触发完成"); } - Log($"温度数据处理完成"); + Log($"温度数据处理完成,剩余数据包数量: {dataAccumulator.Count}"); } catch (Exception ex) { @@ -1602,6 +1713,97 @@ namespace JoyD.Windows.CS.Toprie } } + /// + /// 在字节数组中查找头部标识 + /// + /// 要搜索的字节数组 + /// 头部标识字符串 + /// 头部标识的起始索引,未找到返回-1 + private int FindHeader(byte[] data, string headerMarker) + { + byte[] headerBytes = Encoding.ASCII.GetBytes(headerMarker); + + for (int i = 0; i <= data.Length - headerBytes.Length; i++) + { + bool match = true; + for (int j = 0; j < headerBytes.Length; j++) + { + if (data[i + j] != headerBytes[j]) + { + match = false; + break; + } + } + if (match) + { + return i; + } + } + return -1; + } + + /// + /// 在字节数组的指定范围内查找头部标识 + /// + /// 要搜索的字节数组 + /// 头部标识字符串 + /// 搜索的起始索引 + /// 搜索的结束索引(不包含) + /// 头部标识的起始索引,未找到返回-1 + private int FindHeader(byte[] data, string headerMarker, int startIndex, int endIndex) + { + byte[] headerBytes = Encoding.ASCII.GetBytes(headerMarker); + + // 确保参数有效 + if (startIndex < 0) + startIndex = 0; + if (endIndex > data.Length) + endIndex = data.Length; + if (startIndex >= endIndex) + return -1; + + // 调整结束索引,确保有足够空间容纳完整的头部标识 + int adjustedEndIndex = endIndex - headerBytes.Length + 1; + if (startIndex >= adjustedEndIndex) + return -1; + + for (int i = startIndex; i < adjustedEndIndex; i++) + { + bool match = true; + for (int j = 0; j < headerBytes.Length; j++) + { + if (data[i + j] != headerBytes[j]) + { + match = false; + break; + } + } + if (match) + { + return i; + } + } + return -1; + } + + /// + /// 根据头部计算数据长度 + /// + /// 包含头部的字节数组 + /// 数据长度 + private int CalculateDataLength(byte[] headerData) + { + // 这里需要根据实际的头部格式来解析数据长度 + // 假设头部的第5-8字节包含数据长度信息(4字节整数) + // 实际实现需要根据设备的协议规范进行调整 + if (headerData.Length >= 9) // 确保至少有9字节头部 + { + // 假设数据长度是固定的:256x192分辨率,每个温度值2字节 + return 256 * 192 * 2; + } + return 0; + } + /// /// 触发温度数据接收事件 /// @@ -5759,5 +5961,30 @@ namespace JoyD.Windows.CS.Toprie // 移除内部的TemperatureData类定义,使用全局的TemperatureData类 #endregion 温度相关辅助类 + + /// + /// 清理TCP连接资源的辅助方法 + /// + private void CleanupConnectionResources(NetworkStream stream, TcpClient tcpClient, out NetworkStream cleanedStream, out TcpClient cleanedTcpClient) + { + try + { + if (stream != null) + { + stream.Close(); + } + if (tcpClient != null) + { + tcpClient.Close(); + } + } + catch (Exception ex) + { + Log($"清理连接资源时发生异常: {ex.Message}"); + } + + cleanedStream = null; + cleanedTcpClient = null; + } } } \ No newline at end of file