|
|
@@ -0,0 +1,120 @@
|
|
|
+package com.evps.comm.local.xnet.client;
|
|
|
+
|
|
|
+import com.evps.comm.local.config.ApplicationConfig;
|
|
|
+import com.evps.comm.local.dto.CenterDto;
|
|
|
+import com.evps.comm.local.repository.ApplicationRepository;
|
|
|
+import com.evps.comm.local.xnet.client.codec.EvpsLocalClientDecoder;
|
|
|
+import com.evps.comm.local.xnet.client.codec.EvpsLocalClientEncoder;
|
|
|
+import com.evps.comm.local.xnet.client.handler.EvpsLocalClientPacketInboundHandler;
|
|
|
+import io.netty.bootstrap.Bootstrap;
|
|
|
+import io.netty.channel.*;
|
|
|
+import io.netty.channel.socket.SocketChannel;
|
|
|
+import io.netty.handler.logging.LogLevel;
|
|
|
+import io.netty.handler.logging.LoggingHandler;
|
|
|
+import io.netty.handler.timeout.IdleStateHandler;
|
|
|
+import lombok.Getter;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.Setter;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+import java.net.InetSocketAddress;
|
|
|
+import java.util.concurrent.Callable;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Getter
|
|
|
+@Setter
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class EvpsLocalClient implements Callable<Object> {
|
|
|
+
|
|
|
+ private final CenterDto center;
|
|
|
+ private final ApplicationConfig config;
|
|
|
+ private final EvpsLocalClientBootstrapFactory bootstrapFactory;
|
|
|
+ private final EvpsLocalClientPacketInboundHandler evpsLocalClientPacketInboundHandler;
|
|
|
+ private final EvpsLocalClientEncoder evpsLocalClientEncoder;
|
|
|
+
|
|
|
+ private Bootstrap bootstrap = null;
|
|
|
+ private ChannelFuture channelFuture = null;
|
|
|
+ private String ipAddress;
|
|
|
+ private int port;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object call() {
|
|
|
+
|
|
|
+ this.ipAddress = this.center.getIpAddress();
|
|
|
+ this.port = this.center.getCommPort();
|
|
|
+
|
|
|
+ log.info("EvpsLocalClient Start: [{}, {}], {}", this.center.getCenterId(), this.ipAddress, this.port);
|
|
|
+ if (this.bootstrap == null) {
|
|
|
+ this.bootstrap = this.bootstrapFactory.createBootstrap();
|
|
|
+ this.bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.config.getConnectionTimeout() * 1000);
|
|
|
+ this.bootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
|
|
+ // 핸들러가 실행되는 순서는 추가된 순서에 의해 결정된다.(Inbound: head=>tail, Outbound: tail=>head, name2ctx)
|
|
|
+ @Override
|
|
|
+ public void initChannel(SocketChannel ch) {
|
|
|
+ if (center.isCommLogging()) {
|
|
|
+ ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
|
|
|
+ }
|
|
|
+ IdleStateHandler idleStateHandler = new IdleStateHandler(center.getHeartBeat(), 0,0, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ ch.pipeline().addLast("evpsLocalIdleStateHandler", idleStateHandler);
|
|
|
+ ch.pipeline().addLast("evpsLocalClientDecoder", new EvpsLocalClientDecoder()); // Decoding handler
|
|
|
+ ch.pipeline().addLast("evpsLocalClientPacketInboundHandler", evpsLocalClientPacketInboundHandler); // Packet Inbound handler
|
|
|
+ ch.pipeline().addLast("evpsLocalClientEncoder", evpsLocalClientEncoder); // Encoding handler
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("EvpsLocalClient Connect Try: [{}, {}], {}", this.center.getCenterId(), this.ipAddress, this.port);
|
|
|
+ if (this.channelFuture != null && this.channelFuture.channel() != null) {
|
|
|
+ this.channelFuture.channel().close();
|
|
|
+ this.channelFuture = null;
|
|
|
+ }
|
|
|
+ this.channelFuture = this.bootstrap.connect(new InetSocketAddress(this.ipAddress, this.port));
|
|
|
+
|
|
|
+ // 연결 리스너 추가
|
|
|
+ this.channelFuture.addListener(new ChannelFutureListener() {
|
|
|
+ @Override
|
|
|
+ public void operationComplete(ChannelFuture future) {
|
|
|
+ if (future.isSuccess()) {
|
|
|
+ channelOpen(future.channel());
|
|
|
+ } else {
|
|
|
+ log.error("EvpsLocalClient Connect Failed: [{}, {}], {}, Exception {}", center.getCenterId(), center.getIpAddress(), center.getCommPort(), future.cause().getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 연결 종료 리스너 추가
|
|
|
+ this.channelFuture.channel().closeFuture().addListener(new ChannelFutureListener() {
|
|
|
+ @Override public void operationComplete(ChannelFuture future) {
|
|
|
+ channelClosed(future.channel());
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 연결 성공시 처리 이벤트
|
|
|
+ * @param channel
|
|
|
+ */
|
|
|
+ protected void channelOpen(Channel channel) {
|
|
|
+ log.info("EvpsLocalClient Connect Success. [{}, {}], {}, Channel: {}", this.center.getCenterId(), this.center.getIpAddress(), this.center.getCommPort(), channel);
|
|
|
+ ApplicationRepository.setCenterObject(channel, this.center);
|
|
|
+ this.center.getNetState().connect(channel);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 연결 종료시 처리 이벤트
|
|
|
+ * @param channel
|
|
|
+ */
|
|
|
+ protected synchronized void channelClosed(Channel channel) {
|
|
|
+ log.warn("EvpsLocalClient Connect Closed. [{}, {}], {}, Channel: {}", this.center.getCenterId(), this.center.getIpAddress(), this.center.getCommPort(), channel);
|
|
|
+
|
|
|
+ ApplicationRepository.setCenterObject(channel, null);
|
|
|
+ this.center.getNetState().disConnect();
|
|
|
+ channel.close();
|
|
|
+ channel.eventLoop().schedule(this, this.config.getRetryConnectSeconds(), TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|