移除DeviceManager.cs中不必要的锁操作以优化性能
This commit is contained in:
@@ -266,6 +266,42 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
private Thread _temperatureReceiveThread;
|
private Thread _temperatureReceiveThread;
|
||||||
private bool _isReceivingTemperatureData = false;
|
private bool _isReceivingTemperatureData = false;
|
||||||
private bool _isTemperatureReceivingPaused = false; // 暂停标志,用于控制是否处理接收到的温度数据
|
private bool _isTemperatureReceivingPaused = false; // 暂停标志,用于控制是否处理接收到的温度数据
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 准确检测TcpClient连接状态
|
||||||
|
/// 不仅检查Connected属性,还通过Poll方法检测连接是否真正有效
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">要检查的TcpClient实例</param>
|
||||||
|
/// <returns>如果连接有效返回true,否则返回false</returns>
|
||||||
|
private bool IsTcpClientConnected(TcpClient client)
|
||||||
|
{
|
||||||
|
if (client == null || !client.Connected)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查连接状态的标准方法
|
||||||
|
// 100毫秒超时,不读取数据只检测状态
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Poll方法:检查连接状态,100ms超时
|
||||||
|
// SelectMode.SelectRead:检查是否可读
|
||||||
|
bool isConnected = !client.Client.Poll(100, System.Net.Sockets.SelectMode.SelectRead) ||
|
||||||
|
client.Client.Available > 0;
|
||||||
|
|
||||||
|
// 如果连接已断开,Client.RemoteEndPoint会抛出异常
|
||||||
|
if (isConnected)
|
||||||
|
{
|
||||||
|
// 尝试访问RemoteEndPoint验证连接
|
||||||
|
var dummy = client.Client.RemoteEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isConnected;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 任何异常都表示连接可能已断开
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
private ManualResetEvent _stopTemperatureEvent;
|
private ManualResetEvent _stopTemperatureEvent;
|
||||||
private const int TEMPERATURE_TCP_PORT = 8081; // 温度数据TCP端口 - 修正为热像仪SDK文档中指定的端口
|
private const int TEMPERATURE_TCP_PORT = 8081; // 温度数据TCP端口 - 修正为热像仪SDK文档中指定的端口
|
||||||
|
|
||||||
@@ -1125,12 +1161,11 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
// 使用局部变量存储资源
|
// 使用局部变量存储资源
|
||||||
TcpClient localTcpClient = null;
|
TcpClient localTcpClient = null;
|
||||||
NetworkStream localStream = null;
|
NetworkStream localStream = null;
|
||||||
List<byte> temperatureDataAccumulator = new List<byte>();
|
List<byte[]> temperatureDataAccumulator = new List<byte[]>();
|
||||||
byte[] buffer = new byte[65536]; // 缓冲区大小
|
byte[] buffer = new byte[65536]; // 缓冲区大小
|
||||||
|
|
||||||
// 定义常量
|
// 定义常量
|
||||||
const int RECEIVE_TIMEOUT = 30000; // 增加到30秒,减少因超时导致的断开
|
const int RECEIVE_TIMEOUT = 30000; // 增加到30秒,减少因超时导致的断开
|
||||||
const int HEARTBEAT_INTERVAL = 15000; // 心跳间隔15秒
|
|
||||||
const int MEDIUM_SLEEP_MS = 50;
|
const int MEDIUM_SLEEP_MS = 50;
|
||||||
const int LONG_SLEEP_MS = 2000; // 增加重连等待时间
|
const int LONG_SLEEP_MS = 2000; // 增加重连等待时间
|
||||||
const int ERROR_SLEEP_MS = 1000; // 增加异常恢复等待时间
|
const int ERROR_SLEEP_MS = 1000; // 增加异常恢复等待时间
|
||||||
@@ -1165,8 +1200,8 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
temperaturePort = TEMPERATURE_TCP_PORT;
|
temperaturePort = TEMPERATURE_TCP_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 连接管理:仅当连接不存在或已断开时才创建新连接
|
// 连接管理:当连接不存在、已断开或检测到连接不可用时创建新连接
|
||||||
if (localTcpClient == null || !localTcpClient.Connected || localStream == null)
|
if (localTcpClient == null || !IsTcpClientConnected(localTcpClient) || localStream == null)
|
||||||
{
|
{
|
||||||
// 清理之前可能存在的连接资源
|
// 清理之前可能存在的连接资源
|
||||||
try
|
try
|
||||||
@@ -1200,6 +1235,8 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
ReceiveTimeout = RECEIVE_TIMEOUT,
|
ReceiveTimeout = RECEIVE_TIMEOUT,
|
||||||
SendTimeout = RECEIVE_TIMEOUT
|
SendTimeout = RECEIVE_TIMEOUT
|
||||||
};
|
};
|
||||||
|
// 设置接收缓冲区大小
|
||||||
|
localTcpClient.ReceiveBufferSize = 65536; // 64KB
|
||||||
|
|
||||||
Log($"正在连接到温度数据端口 {temperaturePort}...");
|
Log($"正在连接到温度数据端口 {temperaturePort}...");
|
||||||
localTcpClient.Connect(deviceIp, temperaturePort);
|
localTcpClient.Connect(deviceIp, temperaturePort);
|
||||||
@@ -1273,27 +1310,117 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
{
|
{
|
||||||
Log("温度接收已暂停,等待恢复");
|
Log("温度接收已暂停,等待恢复");
|
||||||
Thread.Sleep(MEDIUM_SLEEP_MS);
|
Thread.Sleep(MEDIUM_SLEEP_MS);
|
||||||
|
// 在暂停状态下,仍然需要定期检查连接是否有效
|
||||||
|
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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// 发送心跳保持连接
|
|
||||||
if ((DateTime.Now - lastHeartbeatTime).TotalMilliseconds > HEARTBEAT_INTERVAL)
|
|
||||||
{
|
{
|
||||||
|
// 从暂停状态恢复时,确保连接仍然有效,必要时重新启动数据传输
|
||||||
|
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}");
|
||||||
|
}
|
||||||
|
// 跳出内层循环,回到外层循环重新建立连接
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 如果连接有效但数据传输可能已停止,尝试重新发送开始命令
|
||||||
|
// 这是为了解决暂停后恢复时DataAvailable始终为false的问题
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] heartbeatCommand = Encoding.ASCII.GetBytes("heartbeat\r\n");
|
// 发送开始温度数据传输的命令
|
||||||
localStream.Write(heartbeatCommand, 0, heartbeatCommand.Length);
|
byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n");
|
||||||
|
localStream.Write(startCommand, 0, startCommand.Length);
|
||||||
localStream.Flush();
|
localStream.Flush();
|
||||||
lastHeartbeatTime = DateTime.Now;
|
Log("从暂停状态恢复,重新发送开始温度数据传输命令");
|
||||||
// 心跳不记录日志以减少日志量
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log($"发送心跳失败: {ex.Message}");
|
Log($"重新发送开始命令失败: {ex.Message}");
|
||||||
|
// 发送失败,可能连接已断开,需要重建连接
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (localStream != null)
|
||||||
|
{
|
||||||
|
localStream.Close();
|
||||||
|
localStream = null;
|
||||||
|
}
|
||||||
|
if (localTcpClient != null)
|
||||||
|
{
|
||||||
|
localTcpClient.Close();
|
||||||
|
localTcpClient = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception closeEx)
|
||||||
|
{
|
||||||
|
Log($"关闭失败连接时发生异常: {closeEx.Message}");
|
||||||
|
}
|
||||||
|
// 跳出内层循环,回到外层循环重新建立连接
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用非阻塞方式检查是否有数据可读
|
// 使用非阻塞方式检查是否有数据可读
|
||||||
|
// 先检查连接是否仍然有效
|
||||||
|
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}");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (localStream.DataAvailable)
|
if (localStream.DataAvailable)
|
||||||
{
|
{
|
||||||
// 有数据可读时进行阻塞读取
|
// 有数据可读时进行阻塞读取
|
||||||
@@ -1301,9 +1428,7 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
if (bytesRead > 0)
|
if (bytesRead > 0)
|
||||||
{
|
{
|
||||||
lastReceiveTime = DateTime.Now; // 更新最后接收数据时间
|
lastReceiveTime = DateTime.Now; // 更新最后接收数据时间
|
||||||
byte[] receivedBytes = new byte[bytesRead];
|
Log($"==========================================接收到温度数据字节数: {bytesRead}");
|
||||||
Array.Copy(buffer, receivedBytes, bytesRead);
|
|
||||||
Log($"接收到温度数据字节数: {bytesRead}");
|
|
||||||
|
|
||||||
// 根据暂停状态决定是否处理数据
|
// 根据暂停状态决定是否处理数据
|
||||||
if (isPaused)
|
if (isPaused)
|
||||||
@@ -1312,38 +1437,45 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
byte[] receivedBytes = new byte[bytesRead];
|
||||||
|
Array.Copy(buffer, receivedBytes, bytesRead);
|
||||||
// 同步接收并处理数据
|
// 同步接收并处理数据
|
||||||
lock (temperatureDataAccumulator)
|
temperatureDataAccumulator.Add(receivedBytes);
|
||||||
{
|
ProcessReceivedTemperatureData(temperatureDataAccumulator);
|
||||||
temperatureDataAccumulator.AddRange(receivedBytes);
|
|
||||||
ProcessReceivedTemperatureData(temperatureDataAccumulator);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bytesRead == 0)
|
else if (bytesRead == 0)
|
||||||
|
{
|
||||||
|
// 连接已关闭
|
||||||
|
Log("远程主机关闭了连接");
|
||||||
|
|
||||||
|
// 重置状态标志,下一次循环会创建新连接
|
||||||
|
lock (_lockObject)
|
||||||
{
|
{
|
||||||
// 连接已关闭
|
_isReceivingTemperatureData = false;
|
||||||
Log("远程主机关闭了连接");
|
}
|
||||||
|
|
||||||
// 重置状态标志,下一次循环会创建新连接
|
// 清理连接资源
|
||||||
lock (_lockObject)
|
try
|
||||||
{
|
{
|
||||||
_isReceivingTemperatureData = false;
|
if (localStream != null)
|
||||||
}
|
|
||||||
|
|
||||||
// 清理连接资源
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
localStream.Close();
|
localStream.Close();
|
||||||
localTcpClient.Close();
|
localStream = null;
|
||||||
|
}
|
||||||
|
if (localTcpClient != null)
|
||||||
|
{
|
||||||
|
localTcpClient.Close();
|
||||||
|
localTcpClient = null;
|
||||||
}
|
}
|
||||||
catch {}
|
|
||||||
|
|
||||||
localStream = null;
|
|
||||||
localTcpClient = null;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
localStream = null;
|
||||||
|
localTcpClient = null;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// while循环退出后的处理
|
// while循环退出后的处理
|
||||||
}
|
}
|
||||||
@@ -1422,9 +1554,9 @@ namespace JoyD.Windows.CS.Toprie
|
|||||||
/// 处理接收到的温度数据
|
/// 处理接收到的温度数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dataAccumulator">累积的温度数据</param>
|
/// <param name="dataAccumulator">累积的温度数据</param>
|
||||||
private void ProcessReceivedTemperatureData(List<byte> dataAccumulator)
|
private void ProcessReceivedTemperatureData(List<byte[]> dataAccumulator)
|
||||||
{
|
{
|
||||||
// 根据TemperatureData类的要求,每个温度帧包含9字节头部 + 温度数据
|
//根据TemperatureData类的要求,每个温度帧包含9字节头部 + 温度数据
|
||||||
// 根据注释,设备实际提供的数据分辨率应为256x192,最终映射到512x384显示
|
// 根据注释,设备实际提供的数据分辨率应为256x192,最终映射到512x384显示
|
||||||
const int HEADER_SIZE = 9; // 9字节头部("+TEMP"+数据长度)
|
const int HEADER_SIZE = 9; // 9字节头部("+TEMP"+数据长度)
|
||||||
const int WIDTH = 256;
|
const int WIDTH = 256;
|
||||||
|
|||||||
Reference in New Issue
Block a user