diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs index 4a55c21..b2df931 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs @@ -188,7 +188,7 @@ namespace JoyD.Windows.CS.Toprie } /// - /// 开始接收图像 + /// 开始接收图像(使用HTTP方式) /// private void StartReceiveImage() { @@ -196,7 +196,9 @@ namespace JoyD.Windows.CS.Toprie { if (!_isReceivingImage && _deviceManager.ConnectionStatus == ConnectionStatus.Connected) { - _deviceManager.StartReceiveImage(); + Console.WriteLine("Camera开始使用HTTP方式接收图像"); + // 直接调用HTTP方式的图像接收 + _deviceManager.StartImageReceiving(); _isReceivingImage = true; } } diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs index fce6266..c2c8f2f 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs @@ -1078,6 +1078,7 @@ namespace JoyD.Windows.CS.Toprie /// public void StartImageReceiving() { + Console.WriteLine("开始使用HTTP方式接收图像数据"); try { // 确保之前的连接已关闭 @@ -1157,11 +1158,19 @@ namespace JoyD.Windows.CS.Toprie /// private void ReceiveImageDataWithHttpWebRequest() { + Console.WriteLine($"图像接收线程启动: 使用HTTP请求获取图像数据"); try { - string url = string.Format("http://{0}:8080{1}", DeviceIp, _isInfraredMode ? "/img.jpg" : "/visible.jpg"); + string url = string.Format("http://{0}:8080{1}", DeviceIp, _isInfraredMode ? "/video/infrared.jpg" : "/video/optical.jpg"); while (_isReceivingImages) { + // 确保连接状态正常 + if (_connectionStatus != ConnectionStatus.Connected) + { + Console.WriteLine("连接状态异常,暂停图像接收"); + Thread.Sleep(500); + continue; + } // 添加时间戳避免缓存 string timestampUrl = url + "?t=" + DateTime.Now.Ticks; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(timestampUrl); @@ -1169,6 +1178,7 @@ namespace JoyD.Windows.CS.Toprie request.Timeout = 3000; // 3秒超时 request.KeepAlive = true; request.UserAgent = "Mozilla/5.0"; // 模拟浏览器 + request.ServicePoint.Expect100Continue = false; // 优化HTTP请求性能 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { @@ -1206,8 +1216,19 @@ namespace JoyD.Windows.CS.Toprie // 记录异常并尝试重连 if (_isReceivingImages) { - Console.WriteLine("ReceiveImageDataWithHttpWebRequest error: " + ex.Message); - StartImageReconnect(); + Console.WriteLine($"ReceiveImageDataWithHttpWebRequest error: {ex.Message}"); + // 避免频繁重连 + Thread.Sleep(100); + + // 只有在连接状态为Connected时才尝试图像重连 + if (_connectionStatus == ConnectionStatus.Connected) + { + StartImageReconnect(); + } + else + { + Console.WriteLine("连接已断开,不启动图像重连"); + } } } } @@ -1625,22 +1646,19 @@ namespace JoyD.Windows.CS.Toprie } /// - /// 开始接收图像 + /// 开始接收图像(已弃用,使用HTTP方式替代) /// public void StartReceiveImage() { + Console.WriteLine("已弃用的StartReceiveImage方法,自动切换到HTTP方式"); + if (_connectionStatus != ConnectionStatus.Connected) { throw new InvalidOperationException("设备未连接,无法开始接收图像"); } - ResetStopFlag(); - Thread imageThread = new Thread(ReceiveImageThread) - { - IsBackground = true, - Name = "ImageReceiver" - }; - imageThread.Start(); + // 直接调用HTTP方式的图像接收 + StartImageReceiving(); } /// @@ -1652,12 +1670,23 @@ namespace JoyD.Windows.CS.Toprie } /// - /// 图像接收线程 + /// 图像接收线程 (已弃用,使用HTTP方式替代) /// private void ReceiveImageThread() { + Console.WriteLine("警告: 已弃用的图像接收方式,使用HTTP方式替代"); try { + // 如果调用了这个方法,自动切换到HTTP方式 + if (!_stopRequested.WaitOne(0)) + { + Console.WriteLine("自动切换到HTTP方式获取图像数据"); + if (_imageReceiveThread == null || !_imageReceiveThread.IsAlive) + { + StartImageReceiving(); // 启动HTTP方式 + } + return; + } // 持续获取图像数据 while (!_stopRequested.WaitOne(0)) { @@ -1996,7 +2025,12 @@ namespace JoyD.Windows.CS.Toprie if (_isReconnecting != 0) { Console.WriteLine("检测到正在重连过程中,暂停设备连接"); - UpdateConnectionStatus(ConnectionStatus.Disconnected, "正在进行自动重连,请稍后再试"); + // 保持当前状态,不切换到Disconnected,避免状态闪烁 + // 只输出提示信息,不更改状态 + if (_connectionStatus != ConnectionStatus.Reconnecting) + { + UpdateConnectionStatus(_connectionStatus, "正在进行自动重连,请稍后再试"); + } return; } @@ -2046,8 +2080,9 @@ namespace JoyD.Windows.CS.Toprie _a8Sdk = new A8SDK(_deviceIp); Console.WriteLine("SDK实例创建完成"); - // 验证连接是否成功(通过心跳检测) - Console.WriteLine("尝试发送心跳包进行连接验证...(尝试 1/3)"); + // 注意:设备使用UDP协议通信,不需要建立TCP连接 + // 通过心跳检测来验证设备可达性 + Console.WriteLine("尝试发送UDP心跳包进行设备验证...(尝试 1/3)"); int heartbeatResult = _a8Sdk.Heartbeat(); // 尝试多次心跳检测,增加连接成功率 @@ -2055,22 +2090,22 @@ namespace JoyD.Windows.CS.Toprie while (heartbeatResult <= 0 && retryCount < 3) { retryCount++; - Console.WriteLine($"心跳检测失败,等待500ms后重试...(尝试 {retryCount}/3)"); + Console.WriteLine($"UDP心跳检测失败,等待500ms后重试...(尝试 {retryCount}/3)"); Thread.Sleep(500); heartbeatResult = _a8Sdk.Heartbeat(); } if (heartbeatResult <= 0) { - Console.WriteLine("多次心跳检测均失败"); + Console.WriteLine("多次UDP心跳检测均失败"); // 安全释放SDK实例 if (_a8Sdk != null) { _a8Sdk = null; } - throw new Exception("心跳检测失败,设备可能未响应或端口配置错误"); + throw new Exception("UDP心跳检测失败,设备可能未响应或端口配置错误(应为18890)"); } - Console.WriteLine("心跳检测成功,设备连接有效"); + Console.WriteLine("UDP心跳检测成功,设备连接有效"); // 连接成功 result = true; diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs b/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs index 090ddea..e45592e 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/V8.cs @@ -143,40 +143,40 @@ namespace JoyD.Windows.CS.Toprie { try { - if (isConnected && socket != null && socket.Connected) - return true; - - // 创建Socket连接 - socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - socket.ReceiveTimeout = TIMEOUT; - socket.SendTimeout = TIMEOUT; - socket.Connect(deviceIp, SDK_PORT); + // 注意:设备使用UDP协议通信,不需要建立TCP连接 + // 直接设置连接状态为true,表示准备好进行UDP通信 + // 这里仍然保持isConnected标志,以兼容现有代码逻辑 isConnected = true; + Console.WriteLine($"UDP通信准备就绪,目标设备 {deviceIp}:18890"); return true; } catch (Exception ex) { - Console.WriteLine($"连接设备 {deviceIp} 失败: {ex.Message}"); + Console.WriteLine($"初始化UDP通信失败: {ex.Message}"); isConnected = false; return false; } } - // 断开连接 + // 断开连接(UDP模式下) private void Disconnect() { try { + // 注意:在UDP模式下,不需要关闭socket连接 + // 只需重置连接状态标志 + // 仍然清理socket资源以防万一 if (socket != null) { socket.Close(); socket = null; } isConnected = false; + Console.WriteLine("UDP通信状态已重置"); } catch (Exception ex) { - Console.WriteLine($"断开连接失败: {ex.Message}"); + Console.WriteLine($"重置UDP通信状态失败: {ex.Message}"); } } @@ -184,30 +184,32 @@ namespace JoyD.Windows.CS.Toprie private bool SendCommand(byte[] command, out byte[] response, int responseLength = 0) { response = null; - if (!Connect()) - return false; try { - // 发送命令 - socket.Send(command); - - // 接收响应 - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead = socket.Receive(buffer); - - if (bytesRead > 0) + // 修改为UDP协议,与SDK保持一致 + // SDK中使用的是UDP协议(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) + // 端口使用18890,与SDK中的CMD_SERVER_UDP_PORT保持一致 + using (UdpClient udpClient = new UdpClient()) { - response = new byte[bytesRead]; - Array.Copy(buffer, response, bytesRead); + // 设置接收超时,与SDK中的超时保持一致 + udpClient.Client.ReceiveTimeout = 200; // SDK中普通命令超时为200ms + + // 发送UDP数据报,端口使用18890与SDK保持一致 + udpClient.Send(command, command.Length, deviceIp, 18890); + Console.WriteLine($"UDP命令已发送到 {deviceIp}:18890"); + + // 尝试接收响应 + IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + response = udpClient.Receive(ref remoteEndPoint); + + Console.WriteLine($"收到UDP命令响应,长度: {response.Length}"); return true; } - return false; } catch (Exception ex) { - Console.WriteLine($"发送命令失败: {ex.Message}"); - Disconnect(); + Console.WriteLine($"UDP发送命令失败: {ex.Message}"); return false; } } @@ -216,30 +218,36 @@ namespace JoyD.Windows.CS.Toprie private bool SendCommand(string cmd, out string response) { response = null; - if (!Connect()) - return false; try { - // 发送命令 - byte[] commandBytes = Encoding.ASCII.GetBytes(cmd); - socket.Send(commandBytes); - - // 接收响应 - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead = socket.Receive(buffer); - - if (bytesRead > 0) + // 修改为UDP协议,与SDK保持一致 + // SDK中使用的是UDP协议(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) + // 端口使用18890,与SDK中的CMD_SERVER_UDP_PORT保持一致 + using (UdpClient udpClient = new UdpClient()) { - response = Encoding.ASCII.GetString(buffer, 0, bytesRead); + // 设置接收超时,与SDK中的超时保持一致 + udpClient.Client.ReceiveTimeout = 200; // SDK中普通命令超时为200ms + + // 发送UDP数据报,端口使用18890与SDK保持一致 + byte[] commandBytes = Encoding.ASCII.GetBytes(cmd); + udpClient.Send(commandBytes, commandBytes.Length, deviceIp, 18890); + Console.WriteLine($"UDP命令已发送: {cmd}"); + Console.WriteLine($"目标IP: {deviceIp}:18890"); + + // 尝试接收响应 + IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + byte[] responseBytes = udpClient.Receive(ref remoteEndPoint); + response = Encoding.ASCII.GetString(responseBytes); + + Console.WriteLine($"收到UDP命令响应: {response}"); return true; } - return false; + } catch (Exception ex) { - Console.WriteLine($"发送命令失败: {ex.Message}"); - Disconnect(); + Console.WriteLine($"UDP发送命令失败: {ex.Message}"); return false; } } @@ -1679,29 +1687,55 @@ namespace JoyD.Windows.CS.Toprie { try { - // 设置接收超时,与SDK中的50毫秒保持一致 - udpClient.Client.ReceiveTimeout = 50; + // 注意:SDK中tv_out.tv_sec=50实际表示50秒,这是SDK的实现方式 + // 这里我们设置一个更合理的值500毫秒,既保证能接收到响应,又不会等待太久 + udpClient.Client.ReceiveTimeout = 500; // 发送UDP数据报,端口使用18890与SDK保持一致 udpClient.Send(commandBytes, commandBytes.Length, deviceIp, 18890); - Console.WriteLine("UDP心跳命令已发送"); + Console.WriteLine("UDP心跳命令已发送,等待响应..."); // 尝试接收响应 IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - byte[] responseBytes = udpClient.Receive(ref remoteEndPoint); - string response = Encoding.ASCII.GetString(responseBytes); - Console.WriteLine($"收到UDP心跳响应: {response}"); - - // SDK要求响应中必须包含 ":ok" 字符串才算成功 - if (!string.IsNullOrEmpty(response) && response.Contains(":ok")) + // 使用BeginReceive和EndReceive进行非阻塞接收,更好地处理超时 + IAsyncResult ar = udpClient.BeginReceive(null, null); + if (ar.AsyncWaitHandle.WaitOne(500)) // 额外的超时检查,双重保险 { - Console.WriteLine("心跳成功: 响应包含':ok'"); - return 1; // 返回1表示成功,与DeviceManager中的判断一致 + try + { + byte[] responseBytes = udpClient.EndReceive(ar, ref remoteEndPoint); + string response = Encoding.ASCII.GetString(responseBytes); + + Console.WriteLine($"收到UDP心跳响应: {response}"); + // 不使用LINQ的Select方法,避免缺少System.Linq命名空间的问题 + string[] asciiValues = new string[response.Length]; + for (int i = 0; i < response.Length; i++) + { + asciiValues[i] = ((int)response[i]).ToString(); + } + Console.WriteLine($"响应长度: {response.Length} 字节,响应ASCII码: {string.Join(",", asciiValues)}"); + + // SDK要求响应中必须包含 ":ok" 字符串才算成功 + if (!string.IsNullOrEmpty(response) && response.Contains(":ok")) + { + Console.WriteLine("心跳成功: 响应包含':ok'"); + return 1; // 返回1表示成功,与DeviceManager中的heartbeatResult > 0判断一致 + } + else + { + Console.WriteLine($"心跳响应不包含':ok',验证失败。收到的响应: '{response}'"); + } + } + catch (Exception ex) + { + Console.WriteLine($"处理UDP响应时发生异常: {ex.Message}"); + } } else { - Console.WriteLine("心跳响应不包含':ok',验证失败"); + Console.WriteLine("UDP接收超时,取消接收操作"); + udpClient.Close(); // 关闭以取消接收操作 } } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut) @@ -1722,8 +1756,8 @@ namespace JoyD.Windows.CS.Toprie } } - // 3次尝试都失败 - Console.WriteLine("三次心跳检测均失败"); + // 所有重试都失败了 + Console.WriteLine("三次心跳检测均失败,连接未建立"); return -1; } catch (Exception ex)