From b6585973ca3e9b8e0ea681cd582138a1e7e3f0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Sat, 28 Sep 2024 15:11:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A9=BF=E6=A2=AD=E8=BD=A6=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/config/ConfigProperties.java | 1 + .../web/controller/PLCController.java | 21 +++- .../zhehekeji/web/service/InitService.java | 56 ++++++--- .../com/zhehekeji/web/service/PlcService.java | 2 +- .../com/zhehekeji/web/service/StreetConn.java | 3 +- .../web/service/ksec/KsecNettyClient.java | 4 +- .../shuttleCar/ShuttleNettyClient.java | 108 ++++++++++++++++++ .../shuttleCar/ShuttleNettyFilter.java | 45 ++++++++ .../shuttleCar/ShuttleNettyHandler.java | 71 ++++++++++++ web/src/main/resources/application-prod.yml | 7 ++ 10 files changed, 298 insertions(+), 20 deletions(-) create mode 100644 web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyClient.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyFilter.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyHandler.java diff --git a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java index f64a3d3..8a4c13b 100644 --- a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java +++ b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java @@ -32,6 +32,7 @@ public class ConfigProperties { private String userUrl; private KSEC ksec; + private KSEC shuttleCar; private LightSource lightSource; diff --git a/web/src/main/java/com/zhehekeji/web/controller/PLCController.java b/web/src/main/java/com/zhehekeji/web/controller/PLCController.java index ac53d0a..3d53379 100644 --- a/web/src/main/java/com/zhehekeji/web/controller/PLCController.java +++ b/web/src/main/java/com/zhehekeji/web/controller/PLCController.java @@ -8,6 +8,7 @@ import com.zhehekeji.web.mapper.StreetMapper; import com.zhehekeji.web.service.*; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.robotic.NettyClient; +import com.zhehekeji.web.service.shuttleCar.ShuttleNettyClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; @@ -32,15 +33,27 @@ public class PLCController { @Resource private KsecNettyClient ksecNettyClient; + @Resource + private ShuttleNettyClient shuttleNettyClient; + + @GetMapping("/tcp") @ApiOperation(value = "连接plc,发起请求") public Result tcp(@RequestParam Integer id){ if(configProperties.getServerMode() == 1){ - try { - ksecNettyClient.createClient(configProperties.getKsec()); - }catch (Exception e){ - Assert.isTrue(false,"连接失败,ip:"+configProperties.getKsec().getIp()+",port:"+configProperties.getKsec().getPort()); + if(id==1) { + try { + ksecNettyClient.createClient(configProperties.getKsec()); + } catch (Exception e) { + Assert.isTrue(false, "连接失败,ip:" + configProperties.getKsec().getIp() + ",port:" + configProperties.getKsec().getPort()); + } + }else { + try { + shuttleNettyClient.createClient(configProperties.getShuttleCar()); + } catch (Exception e) { + Assert.isTrue(false, "连接失败,ip:" + configProperties.getShuttleCar().getIp() + ",port:" + configProperties.getShuttleCar().getPort()); + } } }else { diff --git a/web/src/main/java/com/zhehekeji/web/service/InitService.java b/web/src/main/java/com/zhehekeji/web/service/InitService.java index 33cc2a9..7adecfd 100644 --- a/web/src/main/java/com/zhehekeji/web/service/InitService.java +++ b/web/src/main/java/com/zhehekeji/web/service/InitService.java @@ -11,6 +11,7 @@ import com.zhehekeji.web.mapper.CameraMapper; import com.zhehekeji.web.mapper.StreetMapper; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.robotic.NettyClient; +import com.zhehekeji.web.service.shuttleCar.ShuttleNettyClient; import com.zhehekeji.web.service.sick.SickNettyClient; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; @@ -42,6 +43,10 @@ public class InitService implements ApplicationRunner { @Resource private KsecNettyClient ksecNettyClient; + @Resource + private ShuttleNettyClient shuttleNettyClient; + + @Resource private ConfigProperties configProperties; @@ -85,6 +90,8 @@ public class InitService implements ApplicationRunner { LoginThread loginThread = new LoginThread(camera); loginThread.start(); }); + + TaskDelayExecutor.runMp4DownloadExecutor(); LPLicense.createLicKeyIfNotExist(); //plc连接 if(configProperties.getServerMode() == 0){ @@ -101,21 +108,44 @@ public class InitService implements ApplicationRunner { } }); }else if(configProperties.getServerMode() == 1){ - log.info("KESC JSON MODE"); - // 昆船协议 - ConfigProperties.KSEC ksec = configProperties.getKsec(); - if(ksec != null){ - StreetConn.init(1,"ksec"); - try { - ksecNettyClient.createClient(ksec); - }catch (Exception e){ - log.error("kesc connect error,url:{},port:{}",ksec.getIp(),ksec.getPort()); + Thread thread = new Thread(()->{ + log.info("KESC JSON MODE"); + // 昆船协议 + ConfigProperties.KSEC ksec = configProperties.getKsec(); + if(ksec != null){ + StreetConn.init(1,"ksec"); + try { + ksecNettyClient.createClient(ksec); + }catch (Exception e){ + ksecNettyClient.reconnect(1); + log.error("kesc connect error,url:{},port:{}",ksec.getIp(),ksec.getPort()); + } + }else { + log.error("ksec no config"); } - }else { - log.error("ksec no config"); - } + }); + thread.start(); + + Thread thread1 = new Thread(()->{ + + log.info("shuttleCar JSON MODE"); + ConfigProperties.KSEC shuttleCar = configProperties.getShuttleCar(); + if(shuttleCar != null){ + StreetConn.init(0,"shuttleCar"); + try { + shuttleNettyClient.createClient(shuttleCar); + }catch (Exception e){ + shuttleNettyClient.reconnect(0); + log.error("shuttleCar connect error,url:{},port:{}",shuttleCar.getIp(),shuttleCar.getPort()); + } + }else { + log.error("shuttleCar no config"); + } + }); + thread1.start(); + + } - TaskDelayExecutor.runMp4DownloadExecutor(); } class LoginThread extends Thread{ diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcService.java b/web/src/main/java/com/zhehekeji/web/service/PlcService.java index cda82b5..e8e885a 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -87,7 +87,7 @@ public class PlcService { private static String originalPoint = "C6"; public Integer plcStatus() { - Integer count = 1; + Integer count = 2; if(configProperties.getServerMode() == 0){ count = streetMapper.selectCount(new QueryWrapper<>()); } diff --git a/web/src/main/java/com/zhehekeji/web/service/StreetConn.java b/web/src/main/java/com/zhehekeji/web/service/StreetConn.java index 5e8dec3..e020463 100644 --- a/web/src/main/java/com/zhehekeji/web/service/StreetConn.java +++ b/web/src/main/java/com/zhehekeji/web/service/StreetConn.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * PLC连接状态 @@ -16,7 +17,7 @@ import java.util.Map; @Data public class StreetConn { - private static Map connMap = new HashMap<>(); + private static Map connMap = new ConcurrentHashMap<>(); /** * plc连接成功 diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java index 7e5d816..af46ff8 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java @@ -74,7 +74,9 @@ public class KsecNettyClient { } catch (Exception e) { //没连上 继续 log.error("reconnect error num:{}", num); - channel.close(); + if(channel != null) { + channel.close(); + } num++; try { Thread.sleep(ksec.getReconnectInterval()*1000); diff --git a/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyClient.java b/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyClient.java new file mode 100644 index 0000000..7f23415 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyClient.java @@ -0,0 +1,108 @@ +package com.zhehekeji.web.service.shuttleCar; + + +import com.zhehekeji.common.util.FileUtil; +import com.zhehekeji.web.config.ConfigProperties; +import com.zhehekeji.web.service.PlcService; +import com.zhehekeji.web.service.ksec.KsecDecoder; +import com.zhehekeji.web.service.ksec.KsecInfo; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; + +@Slf4j +@Component +public class ShuttleNettyClient { + + private static EventLoopGroup group = new NioEventLoopGroup(); + @Resource + private PlcService plcService; + @Resource + private ConfigProperties configProperties; + + + private static Channel channel; + + public void createClient(ConfigProperties.KSEC ksec) throws InterruptedException { + String lotnum = FileUtil.getText("lastLotnum"); + if(lotnum != null){ + KsecDecoder.setLastLotnum(lotnum); + } + if (StringUtils.isEmpty(ksec.getIp()) || ksec.getPort() == null) { + return; + } + Bootstrap client = new Bootstrap(); + client.group(group); + client.channel(NioSocketChannel.class); + KsecInfo heart = KsecInfo.heart(); + client.handler(new ShuttleNettyFilter(heart, plcService,this)); + // 连接服务端 + + channel = client.connect(ksec.getIp(), ksec.getPort()).sync().channel(); + + } + + /** + * 断线重连 尝试 RECONNECT_NUM 次 + * + * @param upId + */ + public void reconnect(Integer upId) { + Boolean isConnected = false; + int num = 0; + ConfigProperties.KSEC ksec = configProperties.getShuttleCar(); + if (ksec == null) { + log.error("reconnect ,upPc is null ,id:{}", upId); + return; + } + try { + Thread.sleep(1500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + /** + * 重连最大次数 + */ + while ((ksec.getReconnectNum() == -1 || num < ksec.getReconnectNum() ) && !isConnected) { + try { + createClient(ksec); + } catch (Exception e) { + //没连上 继续 + log.error("reconnect error num:{}", num); + if(channel != null) { + channel.close(); + } + num++; + try { + Thread.sleep(ksec.getReconnectInterval()*1000); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + continue; + } + isConnected = true; + } + if (isConnected) { + log.info("plc reconnect success"); + } else { + log.error("plc reconnect error .upPcId:{},reconnect num:{},ip:{},port:{}", upId, num, ksec.getIp(), ksec.getPort()); + } + } + + public static void write(KsecInfo ksecInfo){ + if(channel != null){ + channel.writeAndFlush(ksecInfo); + }else { + log.error(" no connected upPc"); + } + + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyFilter.java b/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyFilter.java new file mode 100644 index 0000000..59319c7 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyFilter.java @@ -0,0 +1,45 @@ +package com.zhehekeji.web.service.shuttleCar; + +import com.zhehekeji.web.service.PlcService; +import com.zhehekeji.web.service.ksec.*; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.timeout.IdleStateHandler; + +import java.util.concurrent.TimeUnit; + +/** + * 客户端过滤器,编解码和心跳的设置 + * + * @author Administrator + * + */ +public class ShuttleNettyFilter extends ChannelInitializer { + + private KsecInfo ksecInfo; + + private PlcService plcService; + + private ShuttleNettyClient nettyClient; + + public ShuttleNettyFilter(KsecInfo ksecInfo, PlcService plcService, ShuttleNettyClient nettyClient){ + this.ksecInfo = ksecInfo; + this.plcService = plcService; + this.nettyClient = nettyClient; + + } + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline ph = ch.pipeline(); + //4秒发一次心跳 + ph.addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); + ByteBuf byteBuf = Unpooled.copiedBuffer(">".getBytes()); + ph.addLast(new KsecDecoder(10000,byteBuf,plcService)); + ph.addLast(new KescEncoder()); + ph.addLast(new ShuttleNettyHandler(ksecInfo,nettyClient)); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyHandler.java b/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyHandler.java new file mode 100644 index 0000000..d023a6b --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/shuttleCar/ShuttleNettyHandler.java @@ -0,0 +1,71 @@ +package com.zhehekeji.web.service.shuttleCar; + +import com.zhehekeji.web.service.StreetConn; +import com.zhehekeji.web.service.ksec.KsecInfo; +import com.zhehekeji.web.service.ksec.KsecNettyClient; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.timeout.IdleStateEvent; +import lombok.extern.slf4j.Slf4j; + +/** + * 与PLC心跳 处理 + * + * @author Administrator + * + */ +@Slf4j +public class ShuttleNettyHandler extends ChannelInboundHandlerAdapter { + /** 客户端请求的心跳命令 */ + private KsecInfo heart; + + + private ShuttleNettyClient nettyClient; + + public ShuttleNettyHandler(KsecInfo ksecInfo, ShuttleNettyClient nettyClient){ + + this.heart = ksecInfo; + this.nettyClient = nettyClient; + } + + /** + * 建立连接时 + */ + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + log.info("upPc connected "); + StreetConn.conn(0); + ctx.fireChannelActive(); + } + + /** + * 关闭连接时 + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.info("upPc closed"); + StreetConn.disConn(0); + log.info(" streetId reconnect......"); + nettyClient.reconnect(0); + } + + /** + * 心跳请求处理,每4秒发送一次心跳请求; + * + */ + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { + if (obj instanceof IdleStateEvent) { + log.debug("upPc send heart"); + ctx.channel().writeAndFlush(heart); + IdleStateEvent event = (IdleStateEvent) obj; + +// if (IdleState.WRITER_IDLE.equals(event.state())) { // 如果写通道处于空闲状态就发送心跳命令 +// +// } + } + + } + + +} diff --git a/web/src/main/resources/application-prod.yml b/web/src/main/resources/application-prod.yml index f8d3cee..2383a12 100644 --- a/web/src/main/resources/application-prod.yml +++ b/web/src/main/resources/application-prod.yml @@ -67,6 +67,13 @@ ksec: reconnectNum: -1 #重连间隔 默认10s reconnectInterval: 10 +shuttleCar: + ip: 127.0.0.1 + port: 8002 + #重连次数 默认10次 + reconnectNum: -1 + #重连间隔 默认10s + reconnectInterval: 10 # ------------ 实时视频流 全部页面的格式 行列数量 videoStyleConfig: videoStyleRow: 4