|
|
|
|
@ -109,6 +109,12 @@ public class S7MultiPlcService {
|
|
|
|
|
// 读取间隔(ms)
|
|
|
|
|
private static final int READ_INTERVAL = 1000;
|
|
|
|
|
|
|
|
|
|
// 重连最大重试次数
|
|
|
|
|
private static final int RECONNECT_MAX_RETRIES = 5;
|
|
|
|
|
|
|
|
|
|
// 重连间隔(ms)
|
|
|
|
|
private static final int RECONNECT_INTERVAL = 3000;
|
|
|
|
|
|
|
|
|
|
// 线程池
|
|
|
|
|
private ExecutorService executorService;
|
|
|
|
|
|
|
|
|
|
@ -189,10 +195,16 @@ public class S7MultiPlcService {
|
|
|
|
|
try {
|
|
|
|
|
S7Client client = pool.take();
|
|
|
|
|
if (!client.Connected) {
|
|
|
|
|
PlcData config = getPlcConfig(plcNumber);
|
|
|
|
|
if (config != null) {
|
|
|
|
|
client.ConnectTo(config.getIp(), config.getRack(), config.getSlot());
|
|
|
|
|
client.Disconnect();
|
|
|
|
|
// 用带重试的方法重新连接
|
|
|
|
|
S7Client newClient = reconnectWithRetry(plcNumber);
|
|
|
|
|
if (newClient != null) {
|
|
|
|
|
return newClient;
|
|
|
|
|
}
|
|
|
|
|
// 重连失败,把旧client放回(虽然不可用,至少不丢失池容量)
|
|
|
|
|
log.warn("PLC {} 获取连接时重连失败", plcNumber);
|
|
|
|
|
pool.offer(client);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return client;
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
@ -211,16 +223,45 @@ public class S7MultiPlcService {
|
|
|
|
|
if (client.Connected) {
|
|
|
|
|
pool.offer(client);
|
|
|
|
|
} else {
|
|
|
|
|
// 断开旧连接,尝试重连后放回池中
|
|
|
|
|
client.Disconnect();
|
|
|
|
|
S7Client newClient = reconnectWithRetry(plcNumber);
|
|
|
|
|
if (newClient != null) {
|
|
|
|
|
pool.offer(newClient);
|
|
|
|
|
} else {
|
|
|
|
|
log.warn("PLC {} 归还连接时重连失败,池中剩余: {}/{}", plcNumber, pool.size(), POOL_SIZE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 带重试的重连,尝试多次直到成功或达到上限
|
|
|
|
|
* @return 新连接,失败返回null
|
|
|
|
|
*/
|
|
|
|
|
private S7Client reconnectWithRetry(String plcNumber) {
|
|
|
|
|
PlcData config = getPlcConfig(plcNumber);
|
|
|
|
|
if (config != null) {
|
|
|
|
|
if (config == null) return null;
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i <= RECONNECT_MAX_RETRIES; i++) {
|
|
|
|
|
S7Client newClient = new S7Client();
|
|
|
|
|
int result = newClient.ConnectTo(config.getIp(), config.getRack(), config.getSlot());
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
pool.offer(newClient);
|
|
|
|
|
log.info("PLC {} 重连成功(第{}次尝试)", plcNumber, i);
|
|
|
|
|
return newClient;
|
|
|
|
|
}
|
|
|
|
|
log.warn("PLC {} 重连失败(第{}/{}次),错误码: {}", plcNumber, i, RECONNECT_MAX_RETRIES, result);
|
|
|
|
|
if (i < RECONNECT_MAX_RETRIES) {
|
|
|
|
|
try {
|
|
|
|
|
sleep(RECONNECT_INTERVAL);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log.error("PLC {} 重连失败,已达最大重试次数 {}", plcNumber, RECONNECT_MAX_RETRIES);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -313,9 +354,31 @@ public class S7MultiPlcService {
|
|
|
|
|
|
|
|
|
|
if (result != 0) {
|
|
|
|
|
log.error("PLC {} 读取失败,错误码: {}", plcNumber, result);
|
|
|
|
|
// 断开坏连接,防止僵尸连接被复用
|
|
|
|
|
client.Disconnect();
|
|
|
|
|
returnConnection(plcNumber, client);
|
|
|
|
|
// 重试一次
|
|
|
|
|
S7Client retryClient = getConnection(plcNumber);
|
|
|
|
|
if (retryClient != null) {
|
|
|
|
|
try {
|
|
|
|
|
byte[] retryBuffer = new byte[readLength];
|
|
|
|
|
int retryResult = retryClient.ReadArea(S7.S7AreaDB, config.getReadDataBlock(), 0, readLength, retryBuffer);
|
|
|
|
|
if (retryResult == 0) {
|
|
|
|
|
log.info("PLC {} 重试读取成功", plcNumber);
|
|
|
|
|
buffer = retryBuffer;
|
|
|
|
|
result = 0;
|
|
|
|
|
} else {
|
|
|
|
|
log.error("PLC {} 重试读取仍失败,错误码: {}", plcNumber, retryResult);
|
|
|
|
|
retryClient.Disconnect();
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
returnConnection(plcNumber, retryClient);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (result != 0) {
|
|
|
|
|
return readDataCache.get(plcNumber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PlcReadData data = new PlcReadData();
|
|
|
|
|
data.setPalletNo(readString(buffer, (int) config.getPalletOffset(), getDataTypeSize(config.getPalletDataType())));
|
|
|
|
|
@ -648,6 +711,8 @@ public class S7MultiPlcService {
|
|
|
|
|
log.info("PLC {} 写入拍照结果成功: {}", plcNumber, photoResult);
|
|
|
|
|
} else {
|
|
|
|
|
log.error("PLC {} 写入拍照结果失败,错误码: {}", plcNumber, result);
|
|
|
|
|
// 断开坏连接,防止僵尸连接被复用
|
|
|
|
|
client.Disconnect();
|
|
|
|
|
}
|
|
|
|
|
returnConnection(plcNumber, client);
|
|
|
|
|
return result == 0;
|
|
|
|
|
@ -704,6 +769,7 @@ public class S7MultiPlcService {
|
|
|
|
|
List<S7Client> clients = new ArrayList<>();
|
|
|
|
|
pool.drainTo(clients);
|
|
|
|
|
|
|
|
|
|
// 1. 保留有效连接,清理无效连接
|
|
|
|
|
for (S7Client client : clients) {
|
|
|
|
|
if (client != null && client.Connected) {
|
|
|
|
|
pool.offer(client);
|
|
|
|
|
@ -711,20 +777,25 @@ public class S7MultiPlcService {
|
|
|
|
|
if (client != null) {
|
|
|
|
|
client.Disconnect();
|
|
|
|
|
}
|
|
|
|
|
PlcData config = getPlcConfig(plcNumber);
|
|
|
|
|
if (config != null) {
|
|
|
|
|
S7Client newClient = new S7Client();
|
|
|
|
|
int result = newClient.ConnectTo(config.getIp(), config.getRack(), config.getSlot());
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
pool.offer(newClient);
|
|
|
|
|
cleaned++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 补满连接池到POOL_SIZE(带重试)
|
|
|
|
|
int currentSize = pool.size();
|
|
|
|
|
for (int i = currentSize; i < POOL_SIZE; i++) {
|
|
|
|
|
log.info("PLC {} 连接池不足({}/{}),尝试补充...", plcNumber, currentSize, POOL_SIZE);
|
|
|
|
|
S7Client newClient = reconnectWithRetry(plcNumber);
|
|
|
|
|
if (newClient != null) {
|
|
|
|
|
pool.offer(newClient);
|
|
|
|
|
} else {
|
|
|
|
|
log.error("PLC {} 补充连接失败,当前池大小: {}/{}", plcNumber, pool.size(), POOL_SIZE);
|
|
|
|
|
break; // 重试都失败了,不再继续补
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cleaned > 0) {
|
|
|
|
|
log.info("PLC {} 替换了 {} 个无效连接", plcNumber, cleaned);
|
|
|
|
|
if (cleaned > 0 || pool.size() < POOL_SIZE) {
|
|
|
|
|
log.info("PLC {} 清理{}个无效连接,当前池大小: {}/{}", plcNumber, cleaned, pool.size(), POOL_SIZE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log.info("PLC连接池清理完成");
|
|
|
|
|
|