翻了翻《Netty 實戰》,看了些概念,仍是以爲似是而非,因而寫了些代碼,通道啥的都建得挺好。可是channelRead0一直收不到消息。
後來東摸西摸,發現我client 建立channel後立刻發消息是不對的,此時channel尚未徹底建好,致使服務端收不到消息。改爲通道active後,server 給 client發送消息,client 收到消息後纔開始向server發消息,此時sever是能收到的。bootstrap
@Slf4j public class ChatServerHandler extends SimpleChannelInboundHandler<String> { public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // 處理handler 添加,全局保存channel log.info("add a handler"); Channel incoming = ctx.channel(); for (Channel channel : channels) { channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n"); } channels.add(ctx.channel()); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // 處理handler 刪除,全局刪除channel Channel incoming = ctx.channel(); for (Channel channel : channels) { channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 離開\n"); } channels.remove(ctx.channel()); } @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { Channel incoming = ctx.channel(); log.info("收到消息: " + msg); for (Channel channel : channels) { if (channel != incoming) { // 羣發給其餘用戶 channel.writeAndFlush("[" + incoming.remoteAddress() + "]" + msg + "\n"); } else { // 迴應當前用戶 channel.writeAndFlush("[響應]" + msg + "\n"); } } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 通道激活,通知client,能夠準備通訊了 Channel incoming = ctx.channel(); log.info("ChatClient:" + incoming.remoteAddress() + "在線"); incoming.writeAndFlush("welcome" + "\n"); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { // 通道失效,client 掉線 Channel incoming = ctx.channel(); log.info("ChatClient:" + incoming.remoteAddress() + "掉線"); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { Channel incoming = ctx.channel(); // 當出現異常就關閉鏈接 log.info("ChatClient:" + incoming.remoteAddress() + "異常"); cause.printStackTrace(); ctx.close(); } }
ServerBootstrap serverBootstrap = new ServerBootstrap(); NioEventLoopGroup bossGroup = new NioEventLoopGroup(); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); serverBootstrap .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler( new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("handler", new ChatServerHandler()); log.info("ChatClient:" + ch.remoteAddress() + "鏈接上"); } } ).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true) .bind(18169);
@Slf4j public class ChatClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { log.info(msg); Channel ch = ctx.channel(); // 收到welcome後,給server發送消息 if(msg.startsWith("welcome")){ ch.writeAndFlush("hello world!" + "\r\n"); ch.writeAndFlush("wish you happy!" + "\r\n"); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); // 出現異常時關閉鏈接 ctx.close(); } }
Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler( new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // 解決粘包問題 pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("handler", new ChatClientHandler()); // log.info("ChatServer:" + ch.remoteAddress() + "鏈接上"); } } ).option(ChannelOption.SO_KEEPALIVE, true); Channel channel = bootstrap.connect("127.0.0.1", 18169).channel(); }