diff --git a/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java b/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java index 28597a8..4e5703c 100644 --- a/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java +++ b/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java @@ -74,7 +74,6 @@ public abstract class BallAPI { bootstrap.group(executors) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) - .option(ChannelOption.SO_KEEPALIVE, true) .handler(BallChannelInitializer.INSTANCE); addListener(new BallListener() { @@ -248,7 +247,7 @@ public abstract class BallAPI { } } - protected void reconnect(int ttl) { + public void reconnect(int ttl) { if (!enabled) { return; } diff --git a/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallChannelInboundHandler.java b/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallChannelHandler.java similarity index 79% rename from hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallChannelInboundHandler.java rename to hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallChannelHandler.java index b65e9ab..9092679 100644 --- a/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallChannelInboundHandler.java +++ b/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallChannelHandler.java @@ -7,18 +7,26 @@ import cn.hamster3.mc.plugin.ball.common.event.server.ServerOfflineEvent; import cn.hamster3.mc.plugin.ball.common.event.server.ServerOnlineEvent; import cn.hamster3.mc.plugin.ball.common.listener.BallListener; import cn.hamster3.mc.plugin.core.common.constant.CoreConstantObjects; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import org.jetbrains.annotations.NotNull; -public class BallChannelInboundHandler extends SimpleChannelInboundHandler { - public static final BallChannelInboundHandler INSTANCE = new BallChannelInboundHandler(); +import java.util.logging.Level; - private BallChannelInboundHandler() { +@ChannelHandler.Sharable +public class BallChannelHandler extends SimpleChannelInboundHandler { + public static final BallChannelHandler INSTANCE = new BallChannelHandler(); + + private BallChannelHandler() { super(true); } @Override protected void channelRead0(ChannelHandlerContext context, String message) { + if ("pong".equals(message)) { + return; + } BallMessageInfo info = CoreConstantObjects.GSON.fromJson(message, BallMessageInfo.class); for (BallListener listener : BallAPI.getInstance().getListeners()) { try { @@ -143,4 +151,36 @@ public class BallChannelInboundHandler extends SimpleChannelInboundHandler { public static final BallChannelInitializer INSTANCE = new BallChannelInitializer(); @@ -22,34 +21,14 @@ public class BallChannelInitializer extends ChannelInitializer @Override protected void initChannel(@NotNull NioSocketChannel channel) { channel.pipeline() + .addLast(new IdleStateHandler(0, 7, 0, TimeUnit.SECONDS)) + .addLast(BallKeepAliveHandler.INSTANCE) .addLast(new LengthFieldPrepender(8)) .addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 8, 0, 8)) .addLast(new StringDecoder(StandardCharsets.UTF_8)) .addLast(new StringEncoder(StandardCharsets.UTF_8)) - .addLast(BallChannelInboundHandler.INSTANCE) - ; + .addLast(BallChannelHandler.INSTANCE); } - @Override - public void channelInactive(@NotNull ChannelHandlerContext context) { - for (BallListener listener : BallAPI.getInstance().getListeners()) { - try { - listener.onConnectInactive(); - } catch (Exception | Error e) { - e.printStackTrace(); - } - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { - for (BallListener listener : BallAPI.getInstance().getListeners()) { - try { - listener.onConnectException(cause); - } catch (Exception | Error e) { - e.printStackTrace(); - } - } - } } diff --git a/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallKeepAliveHandler.java b/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallKeepAliveHandler.java new file mode 100644 index 0000000..cfbcc6e --- /dev/null +++ b/hamster-ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/connector/BallKeepAliveHandler.java @@ -0,0 +1,20 @@ +package cn.hamster3.mc.plugin.ball.common.connector; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleUserEventChannelHandler; +import io.netty.handler.timeout.IdleStateEvent; + +@ChannelHandler.Sharable +public class BallKeepAliveHandler extends SimpleUserEventChannelHandler { + public static final BallKeepAliveHandler INSTANCE = new BallKeepAliveHandler(); + + private BallKeepAliveHandler() { + super(true); + } + + @Override + protected void eventReceived(ChannelHandlerContext context, IdleStateEvent event) { + context.channel().writeAndFlush("ping"); + } +} diff --git a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/Bootstrap.java b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/Bootstrap.java index 7549269..22f47a8 100644 --- a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/Bootstrap.java +++ b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/Bootstrap.java @@ -2,7 +2,7 @@ package cn.hamster3.mc.plugin.ball.server; import cn.hamster3.mc.plugin.ball.server.command.CommandHandler; import cn.hamster3.mc.plugin.ball.server.config.ServerConfig; -import cn.hamster3.mc.plugin.ball.server.connector.BallChannelInitializer; +import cn.hamster3.mc.plugin.ball.server.connector.BallServerChannelInitializer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; @@ -33,8 +33,7 @@ public class Bootstrap { .group(loopGroup) .channel(NioServerSocketChannel.class) .childOption(ChannelOption.TCP_NODELAY, true) - .childOption(ChannelOption.SO_KEEPALIVE, true) - .childHandler(BallChannelInitializer.INSTANCE); + .childHandler(BallServerChannelInitializer.INSTANCE); ChannelFuture channelFuture = bootstrap.bind(ServerConfig.getHost(), ServerConfig.getPort()); channelFuture.addListener(future -> { if (future.isSuccess()) { diff --git a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallChannelHandler.java b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerChannelHandler.java similarity index 55% rename from hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallChannelHandler.java rename to hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerChannelHandler.java index f62f86c..bcae267 100644 --- a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallChannelHandler.java +++ b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerChannelHandler.java @@ -2,33 +2,49 @@ package cn.hamster3.mc.plugin.ball.server.connector; import cn.hamster3.mc.plugin.ball.common.data.BallMessageInfo; import cn.hamster3.mc.plugin.ball.server.constant.ConstantObjects; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BallChannelHandler extends SimpleChannelInboundHandler { - private static final Logger LOGGER = LoggerFactory.getLogger("ChannelHandler"); +@ChannelHandler.Sharable +public class BallServerChannelHandler extends SimpleChannelInboundHandler { + public static final BallServerChannelHandler INSTANCE = new BallServerChannelHandler(); + private static final Logger LOGGER = LoggerFactory.getLogger("BallServerChannelHandler"); - public BallChannelHandler() { + private BallServerChannelHandler() { super(true); } @Override protected void channelRead0(ChannelHandlerContext context, String message) { + if ("ping".equals(message)) { + LOGGER.info("从服务器 {} 上收到一条 ping 消息.", context.channel().remoteAddress()); + context.writeAndFlush("pong"); + return; + } try { BallMessageInfo messageInfo = ConstantObjects.GSON.fromJson(message, BallMessageInfo.class); - LOGGER.info("从服务器 {} 上收到一条消息: \n {}", messageInfo.getSenderID(), messageInfo); - BallChannelInitializer.broadcastMessage(messageInfo); + LOGGER.info("从服务器 {} 上收到一条消息: {}", context.channel().remoteAddress(), messageInfo); + BallServerChannelInitializer.broadcastMessage(messageInfo); } catch (Exception e) { LOGGER.error(String.format("处理消息 %s 时出现错误: ", message), e); } } + @Override + public void channelActive(@NotNull ChannelHandlerContext context) { + LOGGER.warn("与服务器 {} 的连接已可用.", context.channel().remoteAddress()); + } + @Override public void channelInactive(ChannelHandlerContext context) { context.close(); - BallChannelInitializer.CHANNELS.remove(context.channel()); + synchronized (BallServerChannelInitializer.CHANNELS) { + BallServerChannelInitializer.CHANNELS.remove(context.channel()); + } LOGGER.warn("与服务器 {} 的连接已断开.", context.channel().remoteAddress()); } @@ -36,4 +52,4 @@ public class BallChannelHandler extends SimpleChannelInboundHandler { public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { LOGGER.warn("与服务器 {} 通信时出现了一个错误: ", context.channel().remoteAddress(), cause); } -} +} \ No newline at end of file diff --git a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallChannelInitializer.java b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerChannelInitializer.java similarity index 70% rename from hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallChannelInitializer.java rename to hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerChannelInitializer.java index 983240f..f9157e2 100644 --- a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallChannelInitializer.java +++ b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerChannelInitializer.java @@ -9,6 +9,7 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; +import io.netty.handler.timeout.IdleStateHandler; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,20 +17,23 @@ import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; -public class BallChannelInitializer extends ChannelInitializer { - public static final BallChannelInitializer INSTANCE = new BallChannelInitializer(); +public class BallServerChannelInitializer extends ChannelInitializer { + public static final BallServerChannelInitializer INSTANCE = new BallServerChannelInitializer(); public static final List CHANNELS = new ArrayList<>(); - private static final Logger LOGGER = LoggerFactory.getLogger("BallServerCentre"); + private static final Logger LOGGER = LoggerFactory.getLogger("BallServerChannelInitializer"); - private BallChannelInitializer() { + private BallServerChannelInitializer() { } public static void broadcastMessage(BallMessageInfo messageInfo) { String string = messageInfo.toString(); - for (Channel channel : CHANNELS) { - channel.writeAndFlush(string); + synchronized (CHANNELS) { + for (Channel channel : CHANNELS) { + channel.writeAndFlush(string); + } } } @@ -45,13 +49,16 @@ public class BallChannelInitializer extends ChannelInitializer } channel.pipeline() + .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS)) + .addLast(BallServerKeepAliveHandler.INSTANCE) .addLast(new LengthFieldPrepender(8)) .addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 8, 0, 8)) .addLast(new StringDecoder(StandardCharsets.UTF_8)) .addLast(new StringEncoder(StandardCharsets.UTF_8)) - .addLast(new BallChannelHandler()); + .addLast(BallServerChannelHandler.INSTANCE); - CHANNELS.add(channel); + synchronized (CHANNELS) { + CHANNELS.add(channel); + } } - } diff --git a/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerKeepAliveHandler.java b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerKeepAliveHandler.java new file mode 100644 index 0000000..109a09f --- /dev/null +++ b/hamster-ball-server/src/main/java/cn/hamster3/mc/plugin/ball/server/connector/BallServerKeepAliveHandler.java @@ -0,0 +1,28 @@ +package cn.hamster3.mc.plugin.ball.server.connector; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleUserEventChannelHandler; +import io.netty.handler.timeout.IdleStateEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ChannelHandler.Sharable +public class BallServerKeepAliveHandler extends SimpleUserEventChannelHandler { + public static final BallServerKeepAliveHandler INSTANCE = new BallServerKeepAliveHandler(); + + private static final Logger LOGGER = LoggerFactory.getLogger("BallServerKeepAliveHandler"); + + private BallServerKeepAliveHandler() { + super(true); + } + + @Override + protected void eventReceived(ChannelHandlerContext context, IdleStateEvent event) { + context.close(); + synchronized (BallServerChannelInitializer.CHANNELS) { + BallServerChannelInitializer.CHANNELS.remove(context.channel()); + } + LOGGER.warn("由于无法验证连接存活,与服务器 {} 的连接已断开.", context.channel().remoteAddress()); + } +} diff --git a/hamster-ball-server/src/main/resources/log4j2.component.properties b/hamster-ball-server/src/main/resources/log4j2.component.properties new file mode 100644 index 0000000..d1b5fe1 --- /dev/null +++ b/hamster-ball-server/src/main/resources/log4j2.component.properties @@ -0,0 +1,2 @@ +log4j2.loggerContextFactory=org.apache.logging.log4j.core.impl.Log4jContextFactory +log4j.configurationFile=log4j2.xml diff --git a/hamster-ball-server/src/main/resources/log4j2.xml b/hamster-ball-server/src/main/resources/log4j2.xml index d521006..dca36b3 100644 --- a/hamster-ball-server/src/main/resources/log4j2.xml +++ b/hamster-ball-server/src/main/resources/log4j2.xml @@ -2,10 +2,10 @@ - + - +