| | |
| | | public static bool Init(string ip, int port) { |
| | | lock (_connectLock) { |
| | | try { |
| | | // 若正在连接中,直接返回 |
| | | // 若正在连接中,直接返回 |
| | | if (_isConnecting) { |
| | | LogHelper.Info("已有连接正在尝试中,禁止重复操作"); |
| | | LogHelper.Info("已有连接正在尝试中,禁止重复操作"); |
| | | return false; |
| | | } |
| | | |
| | | _isConnecting = true; // 标记为连接中 |
| | | |
| | | // 释放旧 Socket(仅在未连接时) |
| | | // 释放旧 Socket (仅在未连接时) |
| | | if (_clientSocket != null && !_clientSocket.Connected) { |
| | | SafeCloseSocket(); |
| | | } |
| | |
| | | } |
| | | catch (SocketException ex) { |
| | | _isConnecting = false; |
| | | LogHelper.Error($"初始化连接失败: {ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | lock (_linkLock) { |
| | | try { |
| | | |
| | | // 若Socket存在但实际已断开,强制清理 |
| | | // 若Socket存在但实际已断开,强制清理 |
| | | if (_clientSocket != null && (_clientSocket.Poll(0, SelectMode.SelectRead) && _clientSocket.Available == 0)) { |
| | | SafeCloseSocket(); |
| | | } |
| | |
| | | // 原有逻辑 |
| | | if (_clientSocket != null && _clientSocket.Connected) { |
| | | //if (ip == _ip && port == _port) { |
| | | LogHelper.Info($"产线已连接,无需重连,IP:{ip},端口:{port}"); |
| | | LogHelper.Info($"产线已连接,无需重连,IP:{ip},端口:{port}"); |
| | | return false; |
| | | //} |
| | | |
| | |
| | | return Init(ip, port); |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"产线重连失败,IP:{ip},端口:{port},异常:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | |
| | | // 仅在连接成功时启动接收 |
| | | if (_clientSocket.Connected) { |
| | | LogHelper.Info($"成功连接到服务端:{_ip}:{_port}"); |
| | | LogHelper.Info($"成功连接到服务端:{_ip}:{_port}"); |
| | | _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null); |
| | | } |
| | | else { |
| | | LogHelper.Info("连接未成功,关闭Socket"); |
| | | LogHelper.Info("连接未成功,关闭Socket"); |
| | | SafeCloseSocket(); |
| | | } |
| | | } |
| | |
| | | LogHelper.Info("连接过程中Socket被释放"); |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"连接失败:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | SafeCloseSocket(); |
| | | } |
| | | finally { |
| | |
| | | _clientSocket.Close(); |
| | | _clientSocket.Dispose(); |
| | | |
| | | // 断开后:清除对应IP:Port的接收数据 |
| | | // 断开后:清除对应IP:Port的接收数据 |
| | | string key = $"{_ip}:{_port}"; |
| | | if (_receivedDataQueue.ContainsKey(key)) { |
| | | _receivedDataQueue.Remove(key); |
| | | LogHelper.Info($"已清理队列数据,Key:{key}"); |
| | | LogHelper.Info($"已清理队列数据,Key:{key}"); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"释放Socket资源异常:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | finally { |
| | | _clientSocket = null; |
| | |
| | | _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null); |
| | | } |
| | | else { |
| | | // 服务端主动关闭连接,触发清理 |
| | | // 服务端主动关闭连接,触发清理 |
| | | LogHelper.Info("连接已被服务端关闭"); |
| | | SafeCloseSocket(); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"接收数据异常:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | SafeCloseSocket(); // 异常时主动关闭 |
| | | } |
| | | } |
| | |
| | | //read = result; |
| | | return false; |
| | | } |
| | | LogHelper.Info($"读产线托盘下线数据成功:{BitConverter.ToString(result)}"); |
| | | LogHelper.Info($"读产线托盘下线数据成功:{BitConverter.ToString(result)}"); |
| | | read = result; |
| | | return true; |
| | | } |
| | | else { |
| | | //LogHelper.Info($"_clientSocket={_clientSocket} connected={_clientSocket?.Connected}"); |
| | | Link(_ip, _port); |
| | | LogHelper.Info($"读产线托盘下线数据失败(未连接),准备重连"); |
| | | LogHelper.Info($"读产线托盘下线数据失败 (未连接) ,准备重连"); |
| | | return false; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | //LogHelper.Error($"读产线托盘下线数据失败(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | /* 异常处理 */ |
| | |
| | | /// <param name="registers">Modbus寄存器数组</param> |
| | | /// <returns>字节数组</returns> |
| | | public static byte[] ConvertRegistersToBytes(ushort[] registers) { |
| | | // 每个寄存器是16位(2字节),所以总字节数是寄存器数量的2倍 |
| | | // 每个寄存器是16位(2字节),所以总字节数是寄存器数量的2倍 |
| | | byte[] bytes = new byte[registers.Length * 2]; |
| | | |
| | | for (int i = 0; i < registers.Length; i++) { |
| | | // Modbus使用大端序,高位字节在前 |
| | | // Modbus使用大端序,高位字节在前 |
| | | bytes[i * 2] = (byte)(registers[i] >> 8); // 高位字节 |
| | | bytes[i * 2 + 1] = (byte)(registers[i] & 0xFF); // 低位字节 |
| | | } |
| | |
| | | public static string ConvertBytesToString(byte[] bytes) { |
| | | // 查找第一个0x00字节(字符串结束符)的位置 |
| | | int length = Array.IndexOf(bytes, (byte)0); |
| | | if (length < 0) length = bytes.Length; // 如果没有结束符,使用全部字节 |
| | | if (length < 0) length = bytes.Length; // 如果没有结束符,使用全部字节 |
| | | |
| | | // 根据设备使用的编码转换(常见的有ASCII或UTF-8) |
| | | // 这里使用ASCII编码作为示例,实际应根据设备文档确定编码方式 |
| | | // 这里使用ASCII编码作为示例,实际应根据设备文档确定编码方式 |
| | | return Encoding.ASCII.GetString(bytes, 0, length); |
| | | |
| | | // 如果是UTF-8编码,使用下面这行代替上面那行 |
| | | // 如果是UTF-8编码,使用下面这行代替上面那行 |
| | | // return Encoding.UTF8.GetString(bytes, 0, length); |
| | | } |
| | | |
| | |
| | | } |
| | | else { |
| | | Link(_ip, _port); |
| | | LogHelper.Info($"写电梯入货数据失败(未连接):{Encoding.UTF8.GetString(sends)}"); |
| | | LogHelper.Info($"写电梯入货数据失败 (未连接) :{Encoding.UTF8.GetString(sends)}"); |
| | | return false; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"写电梯入货数据失败(发送了异常):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | try { |
| | | if (_clientSocket != null && _clientSocket?.Connected == true) { |
| | | _receivedDataQueue.TryGetValue($"{_ip}:{_port}", out byte[] result); |
| | | LogHelper.Info($"读电梯出货数据成功:{BitConverter.ToString(result)}"); |
| | | LogHelper.Info($"读电梯出货数据成功:{BitConverter.ToString(result)}"); |
| | | return result; |
| | | } |
| | | else { |
| | | Link(_ip, _port); |
| | | LogHelper.Info($"读电梯出货数据失败(未连接),准备重连"); |
| | | LogHelper.Info($"读电梯出货数据失败 (未连接) ,准备重连"); |
| | | return null; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"读电梯出货数据失败(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return null; |
| | | /* 异常处理 */ |
| | | } |
| | |
| | | |
| | | public static string ChekElevator() { |
| | | try { |
| | | var res = "读取电梯数据的model,索引从1开始,满足以下条件才能发任务 \r\n " + |
| | | "字段,isNormal ,是否正常模式,1:正常模式,第7个Byte右侧第一位Bit \r\n" + |
| | | "字段,isValid,当前位置是否有效,1:有效,0:不用管,第9个Byte右侧第一位Bit \r\n" + |
| | | "字段,runMode,电梯运行模式,9=空闲泊停,7=自动运行,第10个Byte\r\n" + |
| | | "字段,isLock_1_Out,一层出口是否占用,1 = 占用,第14个Byte右侧第一位Bit\r\n" + |
| | | "字段,isLock_2_Out,二层出口是否占用,1 = 占用,第14个Byte右侧第二位Bit\r\n" + |
| | | "字段,taskNO,任务号\r\n" + |
| | | "判断电梯是否符合2楼到1楼搬送条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 !isLock_1_Out \r\n" + |
| | | "判断电梯是否符合1楼到成品库区条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 isLock_1_Out\r\n"; |
| | | var res = "读取电梯数据的model,索引从1开始,满足以下条件才能发任务 \r\n " + |
| | | "字段,isNormal ,是否正常模式,1:正常模式,第7个Byte右侧第一位Bit \r\n" + |
| | | "字段,isValid,当前位置是否有效,1:有效,0:不用管,第9个Byte右侧第一位Bit \r\n" + |
| | | "字段,runMode,电梯运行模式,9=空闲泊停,7=自动运行,第10个Byte\r\n" + |
| | | "字段,isLock_1_Out,一层出口是否占用,1 = 占用,第14个Byte右侧第一位Bit\r\n" + |
| | | "字段,isLock_2_Out,二层出口是否占用,1 = 占用,第14个Byte右侧第二位Bit\r\n" + |
| | | "字段,taskNO,任务号\r\n" + |
| | | "判断电梯是否符合2楼到1楼搬送条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 !isLock_1_Out \r\n" + |
| | | "判断电梯是否符合1楼到成品库区条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 isLock_1_Out\r\n"; |
| | | |
| | | |
| | | var isRead = ReadElevatorOutOk(); |
| | | var log = BitConverter.ToString(isRead); |
| | | res += "读取到的电梯byte数组:" + log + "\r\n"; |
| | | res += "读取到的电梯byte数组:" + log + "\r\n"; |
| | | //if (isRead != null && isRead.Length >= 14) { |
| | | // var elevatorReadInfo = new ElevatorReadInfo() { |
| | | // isNormal = (isRead[6] & 1) == 1, |
| | |
| | | |
| | | // var res1 = elevatorReadInfo.is2To1Ok(); |
| | | |
| | | // res += "判断电梯是否符合2楼到1楼搬送条件,如果符合则返回true,结果" + res1 + "\r\n"; |
| | | // res += "判断电梯是否符合2楼到1楼搬送条件,如果符合则返回true,结果" + res1 + "\r\n"; |
| | | |
| | | // var res2 = elevatorReadInfo.is1ToOk(); |
| | | |
| | | // res += "判断电梯是否符合1楼到成品库区条件,如果符合则返回true,结果" + res2 + "\r\n"; |
| | | // res += "判断电梯是否符合1楼到成品库区条件,如果符合则返回true,结果" + res2 + "\r\n"; |
| | | //} |
| | | //else { |
| | | // return "读取电梯状态失败,byte数组要求大于等于14个且不为空"; |
| | | // return "读取电梯状态失败,byte数组要求大于等于14个且不为空"; |
| | | //} |
| | | return res; |
| | | } |
| | |
| | | return false; |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"判断电梯是否断电(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |