I packaged a Tcp client based on Netty, the purpose is to initiate a connection to the server to get data and decode, I designed a main workflow, based on the SpringBoot timed task api, I query the database once every 5 seconds to query the latest full amount of device information, and then check the device’s online information for devices that are not online then re-initiate a connection, here is my main logic, in order to avoid blocking the main thread of the timed task, I use SpringBoot asynchronous api combined with ComptableFutrue to pull device information from the database.connection, the following is my main logic, in order to avoid blocking the main thread of the timed task, I use SpringBoot’s asynchronous api combined with ComptableFutrue to pull device information from the database The main implementation code is as follows TCP Client Manager class:
@Scheduled(cron = "0/5 * * * * ?")
public void checkConnection() {
log.info("check connection at {}", LocalDateTime.now());
unitService.getAll().whenCompleteAsync((res,ex)-> {
if (ex != null) {
log.error("get all units error", ex);
return;
}
for (Unit unit : res) {
Client client = getById(unit.getId());
if (client == null) {
var newClient=createClient(unit);
if (newClient!=null){
CLIENT_MAP.put(unit.getId(), newClient);
}
}
else {
if (!client.isOnline()) {
log.info("client {} is offline, reconnecting...", unit.getId());
client.connectAsync();
}
}
}
});
}
private Client createClient(Unit unit) {
switch (unit.getUnitType()) {
case ELEVATOR,TWIN->{
return new CanTCPClient( unit,propProcessor,canProtocolLoader);
}
case ESCALATOR,TRAVELATOR ->{
return new ModbusClient(unit,propProcessor);
}
default->{
log.error("Unsupported device type: {}", unit);
}
}
return null;
}
public Client getById(Long id) {
return CLIENT_MAP.get(id);
}
TCP client class:
@Slf4j
public class CanTCPClient extends Client{
private static final EventLoopGroup eventLoopGroup= new NioEventLoopGroup();
private final PropProcessor propProcessor;
private final CanProtocolLoader canProtocolLoader;
@Setter
private Channel channel;
public CanTCPClient(Unit unit, PropProcessor propProcessor, CanProtocolLoader canProtocolLoader) {
super(unit);
this.propProcessor = propProcessor;
this.canProtocolLoader = canProtocolLoader;
}
@Override
public boolean isOnline() {
return gatewayOnline&&deviceOnline;
}
@Override
public CompletableFuture<Void> close() {
if (channel == null) {
return CompletableFuture.completedFuture(null);
}
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
ChannelFuture channelFuture = channel.close();
channelFuture.addListener(future -> {
if (future.isSuccess()) {
completableFuture.complete(null);
} else {
completableFuture.completeExceptionally(future.cause());
}
});
return completableFuture;
}
@Override
public void connectAsync(){
String ipAddress = unit.getIpAddress();
int port = unit.getPort();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
.option(ChannelOption.TCP_NODELAY, true);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) {
socketChannel.pipeline()
.addLast(new CanCodec())
.addLast(new DeviceOnlineHandler())
.addLast(new CanFrameDecoder(canProtocolLoader,new BasicDecoder()))
.addLast(propProcessor)
.addLast(new ExceptionHandler());
socketChannel.attr(CLIENT_ATTRIBUTE_KEY).set(CanTCPClient.this);
setChannel(socketChannel);
}
});
ChannelFuture channelFuture= bootstrap.connect(ipAddress, port);
channelFuture.addListener(future -> {
if (future.isSuccess()) {
this.setGatewayOnline(true);
log.info("connect to [{}] can server success,ip={},port={}",unit.getName(), ipAddress, port);
} else {
this.setGatewayOnline(false);
log.error("connect to[{}]CAN server fail,ip={},port={}",unit.getName(), ipAddress, port);
}
});
}
}
After SpringBoot starts up normally I get an exception to the running condition The logs are printed except for the first time when the application starts up after getting the following logs
2024-09-13 13:17:13.821 ERROR [][] [nioEventLoopGroup-5-1] com.rms.session.CanTCPClient:97 - connect to [L1 shaft upper car] CAN gateway fail,ip=192.168.103.113,port=4001
2024-09-13 13:17:13.822 ERROR [][] [nioEventLoopGroup-5-3] com.rms.session.CanTCPClient:97 - connect to [L3 shaft upper car] CAN gateway fail,ip=192.168.200.103,port=4001
The programme seems to be in a stalled state, but not completely blocked, as I have observed that the logs appear randomly at random moments, not once every 5 seconds as I would have expected.
I expect the programme to work according to the vision I’ve described, with the aim of initiating a request to check the connection once every five seconds, and re-initiating the connection for offline clients