欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

netty编码与解码

程序员文章站 2022-03-03 08:06:29
1、编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码 ,codec(编解码器) 的组成部分有两个:decoder(解码器)和 encoder(编码器)。encoder 负责把业务数据转换成字节码数据,decoder 负责把字节码数据转换成业务数据。2、netty提供的编码器和解码器有:StringEncoder,对字符串数据进行编码ObjectEncoder,对 Java 对象进行编码StringDecoder,...

1、编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码 ,codec(编解码器) 的组成部分有两个:decoder(解码器)和 encoder(编码器)。encoder 负责把业务数据转换成字节码数据,decoder 负责把字节码数据转换成业务数据。

2、netty提供的编码器和解码器有:

StringEncoder,对字符串数据进行编码

ObjectEncoder,对 Java 对象进行编码

StringDecoder, 对字符串数据进行解码

ObjectDecoder,对 Java 对象进行解码

MessageToByteEncoder 编码器,这个解码器是一个抽象类,需要实现它提供的方法来完成自己的业务需求。

ByteToMessageDecoder 解码器,这个解码器是一个抽象类,需要实现它提供的方法来完成自己的业务需求。

ReplayingDecoder<s> 解码器,
ReplayingDecoder扩展了ByteToMessageDecoder类,使用这个类,我们不必调用readableBytes()方法。

参数S指定了用户状态管理的类型,其中Void代表不需要状态管理

LineBasedFrameDecoder:这个类在Netty内部也有使用,它使用行尾控制字符(\n或者\r\n)作为分隔符来解析数据。
DelimiterBasedFrameDecoder:使用自定义的特殊字符作为消息的分隔符。
HttpObjectDecoder:一个HTTP数据的解码器
LengthFieldBasedFrameDecoder:通过指定长度来标识整包消息,这样就可以自动的处理黏包和半包消息。

3、使用自定义编码器来进行编码和解码处理消息:

解码器1:

public class MyByteToLongDecoder extends ByteToMessageDecoder {

    /**
     * 解码器的方法
     * @param channelHandlerContext
     * @param byteBuf
     * @param list
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        System.out.println("MyByteToLongDecoder解码器被调用...");
        if(byteBuf.readableBytes() > 8){
            list.add(byteBuf.readLong());
        }

    }
}

解码器2:

public class MyByteToLongDecoder2 extends ReplayingDecoder<Void>{

    /**
     * 街按摩器方法
     * @param channelHandlerContext
     * @param byteBuf
     * @param list
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        //在 ReplayingDecoder 不需要判断数据是否足够读取,内部会进行处理判断
        System.out.println("MyByteToLongDecoder2被调用...");
        list.add(byteBuf.readLong());
    }
}

编码器:

public class MyLongToByteEncoder extends MessageToByteEncoder<Long> {

    /**
     * 编码器处理的方法
     * @param channelHandlerContext 上下文对象
     * @param msg 传送过来的数据
     * @param byteBuf
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Long msg, ByteBuf byteBuf) throws Exception {
        System.out.println("MyLongToByteEncoder encoder 编码器被调用");
        System.out.println("接收到的消息:" + msg);
        //将数据写入到缓冲区
        byteBuf.writeLong(msg);
    }
}

4、使用谷歌的Protobuf来完成编解码器:

Protobuf 是 Google 发布的开源项目,全称 Google Protocol Buffers,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC[远程过程调用  remote procedure call ] 数据交换格式 。

Protobuf基本介绍和使用示意图
Protobuf高性能,高可靠性
使用 protobuf 编译器能自动生成代码,Protobuf 是将类的定义使用.proto 文件进行描述。
然后通过 protoc.exe 编译器根据.proto 自动生成.java 文件Protobuf基本介绍和使用示意图

netty编码与解码

1、编写MyTemplate.proto文件,

//实体类模板,可以有多个类型
syntax = "proto3";
option optimize_for = SPEED;//加快解析
option java_package="com.yu.netty.protobufcodec";//指定生成在哪个包下
option java_outer_classname="MyTemplate"; //外部类名,文件名
//protobuf可以使用message管理其他的message
message MyTemplateData {
       //定义一个枚举类型
       enum DataType {
            StudentType = 0; //在proto3要求enum从0开始
            TeacherType = 1;
       }
       //使用data_type来标识传的是哪一个枚举类型
       DataType data_type = 1;

       //表示每次枚举最多只能出现其中的一个
       oneof dataBody {
            Student student = 2;
            Teacher teacher = 3;
       }
}
//定义学生的信息
message Student {
  int32 id = 1;
  string name = 2;
}
//定义老师的信息
message Teacher {
  int32 id = 1;
  string name = 2;
  int32 age = 3;
}

2、通过protoc.exe文件来生成对应的java文件,命令为:protoc.exe --java_out=. MyTemplate.proto

3、编写对应的客户端和服务器:

服务端代码:

public class ProtoServer {

    public static void main(String[] args) throws Exception{
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //添加解码器
                            pipeline.addLast(new ProtobufDecoder(MyTemplate.MyTemplateData.getDefaultInstance()));
                            //添加自定义的handler
                            pipeline.addLast(new ProtobufHandler());
                        }
                    });
            System.out.println("客户端isok");
            ChannelFuture channelFuture = serverBootstrap.bind(6666).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }

    }
}

服务端对于的handler:

public class ProtobufHandler extends SimpleChannelInboundHandler<MyTemplate.MyTemplateData> {
    /**
     * 读取数据信息
     * @param channelHandlerContext
     * @param myTemplateData
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, MyTemplate.MyTemplateData myTemplateData) throws Exception {
        MyTemplate.MyTemplateData.DataType dataType = myTemplateData.getDataType();
        if(dataType == MyTemplate.MyTemplateData.DataType.StudentType){
            //输出的是学生信息
            MyTemplate.Student student = myTemplateData.getStudent();
            System.out.println("学生的信息为:id=" + student.getId() + ": name=" + student.getName());
        }else if(dataType == MyTemplate.MyTemplateData.DataType.TeacherType){
            //输出的是老师信息
            MyTemplate.Teacher teacher = myTemplateData.getTeacher();
            System.out.println("老师的信息为:id=" + teacher.getId() + ": name=" + teacher.getName() + ":age=" + teacher.getAge());
        }else{
            System.out.println("传入的数据有误....");
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

客户端代码:

public class ProtoClient {

    public static void main(String[] args) throws Exception{
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //添加编码器
                            pipeline.addLast(new ProtobufEncoder());
                            pipeline.addLast(new ProtoClientHandler());
                        }
                    });
            System.out.println("服务端isok");
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6666).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully();
        }

    }
}

客户端对于的handler:

public class ProtoClientHandler extends SimpleChannelInboundHandler<MyTemplate.MyTemplateData> {

    /**
     * 发送数据信息
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       int random = new Random().nextInt(3);
        MyTemplate.MyTemplateData templateData = null;
        if(random == 0){
            templateData = MyTemplate.MyTemplateData.newBuilder()
                    .setDataType(MyTemplate.MyTemplateData.DataType.TeacherType)
                    .setTeacher(MyTemplate.Teacher.newBuilder().setAge(20).setId(1).setName("王老师")).build();
        }else{
            templateData = MyTemplate.MyTemplateData.newBuilder()
                    .setDataType(MyTemplate.MyTemplateData.DataType.StudentType)
                    .setStudent(MyTemplate.Student.newBuilder().setId(1).setName("张三")).build();
        }
        ctx.writeAndFlush(templateData);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, MyTemplate.MyTemplateData myTemplateData) throws Exception {

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

 

 

本文地址:https://blog.csdn.net/qq_27293643/article/details/107673630

相关标签: netty java