• Netty学习篇三 (netty自定义编码解码器)


    本篇将自定义 编码解码器,对数据传输过程进行“入站解码,出站编码”。

    • 服务端接收的是字节数据,通过“入站解码”,得到知道格式的数据;
    • 服务器发送指定格式数据通过 “出站编码” 转换成字节数据,然后发送给客户端;
    • 客户端类似;
    • ChannelPipeLine 管理一系列 ChannelHandler,入站消息解码后转发给下一个 handler 进行处理

    案例需求:客户端或服务器发送 Long 类型数据,出站编码成字节数据,入站解码读取对方发送的消息

    编码器 MyLongToByteEncoder

    package com.oy.inboundandoutbound;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.handler.codec.MessageToByteEncoder;
    
    public class MyLongToByteEncoder extends MessageToByteEncoder<Long> {
        @Override
        protected void encode(ChannelHandlerContext ctx, Long msg, ByteBuf out) throws Exception {
            System.out.println("MyLongToByteEncoder encoder 被调用. msg: " + msg);
            out.writeLong(msg);
        }
    }
    

    解码器 MyByteToLongDecoder

    package com.oy.inboundandoutbound;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.handler.codec.ByteToMessageDecoder;
    
    import java.util.List;
    
    public class MyByteToLongDecoder extends ByteToMessageDecoder {
        /**
         * decode() 会根据接收的数据,被调用多次,知道确定没有新的元素添加到list,
         * 或者是 ByteBuf 没有更多的可读字节为止。
         * 如果 list 不为空,就会将 list 的内容传递给下一个 handler
         * @param ctx 上下文对象
         * @param in 入站后的 ByteBuf
         * @param out 将解码后的数据传递给下一个 handler
         * @throws Exception
         */
        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            // long 类型 为 8 字节
            if (in.readableBytes() >= 8) {
                out.add(in.readLong());
            }
        }
    }
    

    Server 

    package com.oy.inboundandoutbound.server;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    public class Server {
        public static void main(String[] args) {
            NioEventLoopGroup boss = new NioEventLoopGroup(1);
            NioEventLoopGroup work = new NioEventLoopGroup();
    
            try {
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap
                        .group(boss, work)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new MyServerChannelInitializer());
                ChannelFuture future = serverBootstrap.bind(8004).sync();
                System.out.println("server started and listen " + 8004);
                future.channel().closeFuture().sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                boss.shutdownGracefully();
                work.shutdownGracefully();
            }
        }
    }
    package com.oy.inboundandoutbound.server;
    
    import com.oy.inboundandoutbound.MyByteToLongDecoder;
    import com.oy.inboundandoutbound.MyLongToByteEncoder;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    
    public class MyServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            /* 向管道加入处理器 */
            ChannelPipeline pipeline = socketChannel.pipeline();
    
            // 入站的 handler 进行解码
            pipeline.addLast("decoder", new MyByteToLongDecoder());
            // 添加一个出站的 handler 对数据进行编码
            pipeline.addLast("encoder", new MyLongToByteEncoder());
    
            // 添加自定义的处理器
            pipeline.addLast("MyServerHandler", new MyServerHandler());
    
        }
    
    }
    
    package com.oy.inboundandoutbound.server;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    public class MyServerHandler extends SimpleChannelInboundHandler<Long> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Long msg) throws Exception {
            System.out.println("从客户端读到的数据:" + msg);
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            // 服务器返回 long 类型数据
            ctx.writeAndFlush(654321L);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
    

    Client

    package com.oy.inboundandoutbound.client;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    public class Client {
        public static void main(String[] args) {
            NioEventLoopGroup group = new NioEventLoopGroup();
    
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap
                        .group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new MyClientChannelInitializer());
                ChannelFuture future = bootstrap.connect("127.0.0.1", 8004).sync();
                future.channel().closeFuture().sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                group.shutdownGracefully();
            }
        }
    }
    package com.oy.inboundandoutbound.client;
    
    import com.oy.inboundandoutbound.MyByteToLongDecoder;
    import com.oy.inboundandoutbound.MyLongToByteEncoder;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    public class MyClientChannelInitializer extends ChannelInitializer<NioSocketChannel> {
        @Override
        protected void initChannel(NioSocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
    
            // 入站的 handler 进行解码
            pipeline.addLast("decoder", new MyByteToLongDecoder());
            // 添加一个出站的 handler 对数据进行编码
            pipeline.addLast("encoder", new MyLongToByteEncoder());
    
            // 添加自定义 handler,处理业务逻辑
            pipeline.addLast(new MyClientHandler());
        }
    }
    
    package com.oy.inboundandoutbound.client;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    public class MyClientHandler extends SimpleChannelInboundHandler<Long> {
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, Long msg) throws Exception {
            // 客户端读取服务器发送的 long 类型数据
            System.out.println("客户端读取服务器发送的, msg:" + msg);
        }
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            // 客户端发送 long 类型数据
            ctx.writeAndFlush(123456L);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
    

    启动服务器和客户端程序, 控制台打印结果:  

     

    我话讲完!谁赞成?谁反对?
  • 相关阅读:
    关于-webkit-border-image的理解
    手机浏览pc网页,字体显示比样式中设置的字体更大
    网页乱码原理
    浏览器的钉点调试的作用
    zepto中的多点触摸
    parentNode和offsetParent的区别,仅仅只是定位相对不一样么
    ckeckbox的默认样式,label for添加toggle后失效,美化checkbox
    当stop()遇到animate()的回调函数
    有联系的标识变量的变化一定要同步
    当relative遇上z-index,半透明度不阻断事件捕获
  • 原文地址:https://www.cnblogs.com/wffzk/p/15545690.html
Copyright © 2020-2023  润新知