zoukankan      html  css  js  c++  java
  • Netty(2)Echo

    上节介绍的是discard协议,即不给客户端返回消息。本节主要说下,echo协议,即服务端收到消息后原样返回给客户端。

    为了实现此需求,只需要在DiscardServerHandler中重写channelRead()方法,即可。如下:

    @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf in = (ByteBuf) msg;
            log.info("接收并原样返回:{}",in.toString(io.netty.util.CharsetUtil.UTF_8));
            
            ctx.write(msg);//(1)
            ctx.flush();//(2)
        }

    1、ChannelHandlerContext对象提供了很多方法,如:

    ctx.read();
    ctx.write();
    ctx.flust();
    ctx.channel();
    ctx.pipeline();
    ctx.alloc();
    ctx.close();
    ctx.connect();
    ctx.disconnect();

    注意,我们这里没有release 接收到的消息,不像discard例子那样。因为,当消息写到物理网络中后,netty才会在自动release

    在channelRead方法内的最后,加入in.release();即

    @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf in = (ByteBuf) msg;
            log.info("接收并原样返回:{}",in.toString(io.netty.util.CharsetUtil.UTF_8));
            
            ctx.write(msg);//(1)
            ctx.flush();//(2)
            in.release();
        }

    则报异常:io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1

    因此,不能在server端的channelRead方法内加入in.release()。

    当ctx.flush(msg)后,可以在channelReadComplete()方法中release。

    2、ctx.write(object)并不会将消息写到物理网络中,而是在内部buffer中的,需要使用ctx.flush()来写入到物理网络中。当然,也可以使用ctx.writeAndFlush(msg)代替。

    -----telnet测试:

    客户端:

    [root@cent7-zuoys ~]# telnet 10.134.253.10 8080
    Trying 10.134.253.10...
    Connected to 10.134.253.10.
    Escape character is '^]'.
    遥远2
    遥远2

    服务端:16:22:12.636 [nioEventLoopGroup-3-1] 接收并原样返回:遥远2

    -----client测试:

    @Slf4j
    public class EchoClientHandler extends SimpleChannelInboundHandler<Object> {
        private ByteBuf content;
        private ChannelHandlerContext ctx;
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            this.ctx = ctx;
            //content = ctx.alloc().directBuffer(EchoClient.SIZE).writeZero(EchoClient.SIZE);
            content = ctx.alloc().directBuffer(EchoClient.SIZE).writeBytes("遥远2".getBytes(CharsetUtil.UTF_8));
            //发送以上消息
            generatTraffic();
        }
    
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            content.release();
        }
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf in = (ByteBuf) msg;
            log.info("接收消息:{}",in.toString(io.netty.util.CharsetUtil.UTF_8));
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
        //*************************自定义方法
        private void generatTraffic() {
            //flush the outbound buffer to the socket.
            //once flushed,generate the same amount of traffic again.
            ByteBuf buf = content.retainedDuplicate();
            ctx.writeAndFlush(buf).addListener(trafficGenerator);
            //Console.log((char)buf.readByte());
            log.info("发送消息:{}",buf.toString(io.netty.util.CharsetUtil.UTF_8));
        }
        private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (future.isSuccess()) {
                    log.info("success!");
                } else {
                    future.cause().printStackTrace();
                    future.channel().close();
                }
            }
        };
    }

    红字部分,为修改的。在channelRead0方法中,之前是空的,现在是因为,服务端返回消息了,需要在此处接收。

    运行结果:

    客户端:

    16:50:42.443 [nioEventLoopGroup-2-1] success!
    16:50:42.446 [nioEventLoopGroup-2-1] 发送消息:遥远2
    16:50:42.461 [nioEventLoopGroup-2-1] 接收消息:遥远2

    服务端:16:50:42.456 [nioEventLoopGroup-3-1] 接收并原样返回:遥远2


    SimpleChannelInboundHandler 与 ChannelInboundHandlerAdapter区别:

    服务端使用ChannelInboundHandlerAdapter,客户端使用SimpleChannelInboundHandler 。

    因为ChannelInboundHandlerAdapter,在channelRead()内不能release。而SimpleChannelInboundHandler 自动release。

  • 相关阅读:
    Poj 1742 Coins(多重背包)
    Poj 2350 Above Average(精度控制)
    求二进制数中1的个数
    Poj 1659 Distance on Chessboard(国际象棋的走子规则)
    Poj 2411 Mondriaan's Dream(压缩矩阵DP)
    Poj 2136 Vertical Histogram(打印垂直直方图)
    Poj 1401 Factorial(计算N!尾数0的个数——质因数分解)
    poj 2390 Bank Interest(计算本利和)
    Poj 2533 Longest Ordered Subsequence(LIS)
    Poj 1887 Testing the CATCHER(LIS)
  • 原文地址:https://www.cnblogs.com/yaoyuan2/p/9620808.html
Copyright © 2011-2022 走看看