package info.xiaomo.core.network; import info.xiaomo.core.network.handler.MessageDecoder; import info.xiaomo.core.network.handler.MessageEncoder; import info.xiaomo.core.network.handler.MessageExecutor; import info.xiaomo.core.network.handler.WebSocketDecoder; import info.xiaomo.core.network.handler.WebSocketEncoder; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslContext; import io.netty.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.util.concurrent.TimeUnit; /** * @author xiaomo */ public class NetworkServiceImpl implements IService { private static final Logger LOGGER = LoggerFactory.getLogger(NetworkServiceImpl.class); private int port; private EventLoopGroup bossGroup; private EventLoopGroup workerGroup; private ServerBootstrap bootstrap; private ServiceState state; NetworkServiceImpl(final NetworkServiceBuilder builder) { int bossLoopGroupCount = builder.getBossLoopGroupCount(); int workerLoopGroupCount = builder.getWorkerLoopGroupCount(); this.port = builder.getPort(); final SslContext sslCtx; bossGroup = new NioEventLoopGroup(bossLoopGroupCount); workerGroup = new NioEventLoopGroup(workerLoopGroupCount); if (builder.isSsl()) { try { File keyCertChainFile = new File(builder.getSslKeyCertChainFile()); File keyFile = new File(builder.getSslKeyFile()); sslCtx = SslContext.newServerContext(keyCertChainFile, keyFile); } catch (Exception var4) { throw new RuntimeException("sslCtx create failed.", var4); } } else { sslCtx = null; } bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup); bootstrap.channel(NioServerSocketChannel.class); bootstrap.option(ChannelOption.SO_BACKLOG, 1024); bootstrap.childOption(ChannelOption.TCP_NODELAY, true); bootstrap.childOption(ChannelOption.SO_RCVBUF, 128 * 1024); bootstrap.childOption(ChannelOption.SO_SNDBUF, 128 * 1024); bootstrap.handler(new LoggingHandler(LogLevel.DEBUG)); if (builder.isWebSocket()) { bootstrap.childHandler(new WebSocketHandler(builder, sslCtx)); } else { bootstrap.childHandler(new SocketHandler(builder)); } } /** * web socket的handler */ class WebSocketHandler extends ChannelInitializer { private NetworkServiceBuilder builder; private SslContext sslCtx; WebSocketHandler(NetworkServiceBuilder builder, SslContext sslCtx) { this.builder = builder; this.sslCtx = sslCtx; } @Override protected void initChannel(Channel ch) { //添加web socket相关内容 ChannelPipeline pip = ch.pipeline(); if (sslCtx != null) { pip.addLast("sslHandler", sslCtx.newHandler(ch.alloc())); } pip.addLast(new HttpServerCodec()); pip.addLast(new HttpObjectAggregator(65536)); pip.addLast(new WebSocketServerProtocolHandler("/")); pip.addLast(new WebSocketDecoder()); pip.addLast(new WebSocketEncoder()); pip.addLast(new MessageDecoder(builder.getImessageandhandler())); pip.addLast(new MessageExecutor(builder.getConsumer(), builder.getListener())); for (ChannelHandler handler : builder.getExtraHandlers()) { pip.addLast(handler); } } } /** * socket的handler */ class SocketHandler extends ChannelInitializer { private NetworkServiceBuilder builder; SocketHandler(NetworkServiceBuilder builder) { this.builder = builder; } @Override protected void initChannel(Channel ch) { ChannelPipeline pip = ch.pipeline(); int maxLength = 1048576; int lengthFieldLength = 4; int ignoreLength = -4; int offset = 0; pip.addLast(new LengthFieldBasedFrameDecoder(maxLength, offset, lengthFieldLength, ignoreLength, lengthFieldLength)); pip.addLast(new MessageDecoder(builder.getImessageandhandler())); pip.addLast(new LengthFieldPrepender(4, true)); pip.addLast(new MessageEncoder(builder.getImessageandhandler())); pip.addLast(new MessageExecutor(builder.getConsumer(), builder.getListener())); for (ChannelHandler handler : builder.getExtraHandlers()) { pip.addLast(handler); } } } @Override public void start() { try { ChannelFuture f = bootstrap.bind(port); f.sync(); } catch (Exception e) { throw new RuntimeException(e); } this.state = ServiceState.RUNNING; LOGGER.info("Server on port:{} is start", port); } /** * 停止網絡服務 */ @Override public void stop() { this.state = ServiceState.STOPPED; Future<?> bf = bossGroup.shutdownGracefully(); Future<?> wf = workerGroup.shutdownGracefully(); try { bf.get(5000, TimeUnit.MILLISECONDS); wf.get(5000, TimeUnit.MILLISECONDS); } catch (Exception e) { LOGGER.info("Netty服务器关闭失败", e); } LOGGER.info("Netty Server on port:{} is closed", port); } /** * 獲取當前網絡服務狀態 * @return state */ @Override public ServiceState getState() { return this.state; } /** * 服務是否開啟 * @return bool */ @Override public boolean isOpened() { return state == ServiceState.RUNNING; } /** * 服務是否關閉 * @return bool */ @Override public boolean isClosed() { return state == ServiceState.STOPPED; } }