ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Netty框架编解码之ObjectDecoder码流测量

2021-10-09 15:02:22  阅读:255  来源: 互联网

标签:码流 Netty netty 编解码 void io import new public


netty实战a Java object into a ByteBuf码流

1. 背景

java序列化码流比较大,netty提供了一个Java Object到ByteBuf的编码器。

注意使用了ObjectEncoder进行编码的消息,必须使用ObjectDecoder或者ObjectDecoderInputStream进行解码,以保证互操作性。

2. 源码分析

  • ObjectEncoder源码
@Sharable
public class ObjectEncoder extends MessageToByteEncoder<Serializable> {
    private static final byte[] LENGTH_PLACEHOLDER = new byte[4];

    @Override
    protected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf out) throws Exception {
        int startIdx = out.writerIndex();

        ByteBufOutputStream bout = new ByteBufOutputStream(out);
        ObjectOutputStream oout = null;
        try {
            // 四字节长度
            bout.write(LENGTH_PLACEHOLDER);
            oout = new CompactObjectOutputStream(bout);
            // 写入序列化的对象
            oout.writeObject(msg);
            oout.flush();
        } finally {
            if (oout != null) {
                oout.close();
            } else {
                bout.close();
            }
        }

        int endIdx = out.writerIndex();

        out.setInt(startIdx, endIdx - startIdx - 4);
    }
}

3. 实现

3.1 ObjServer

package com.ll.serialization;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
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.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class ObjServer {

	public static final Logger log = LoggerFactory.getLogger(ObjServer.class);
	private final String ip = "127.0.0.1";
    private final String port = "8001";
	
    public void init(){
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap bs = new ServerBootstrap();
        bs.group(bossGroup, workerGroup)
          .channel(NioServerSocketChannel.class)
          .option(ChannelOption.SO_BACKLOG, 1024)
          .childHandler(new ChannelInitializer<Channel>(){
            @Override
            protected void initChannel(Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
                // 服务端解码接收的对象码流
                pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(ClassLoader.getSystemClassLoader())));
                // 服务端返回客户端,编码java对象
                pipeline.addLast(new ObjectEncoder());
                pipeline.addLast(new ObjHandler());
            }
        });

        try {
            ChannelFuture channelFuture = bs.bind(ip, Integer.parseInt(port)).sync();
            log.info("Netty Server 启动成功! Ip: " + channelFuture.channel().localAddress().toString() + " ! ");

            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

3.2 ObjHandler

public class ObjHandler extends ChannelInboundHandlerAdapter {

	public static final Logger log = LoggerFactory.getLogger(ObjHandler.class);
	
	int counter = 0;

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		Dept body = (Dept)msg;
		log.info("this is " + ++counter + " times receive client [" + body.getDeptName() + "]");
		
		ctx.writeAndFlush(body);
	}

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

3.3 ObjClientHandler

使用熟悉的“Hello world!”字符实验。

public class ObjClientHandler extends ChannelInboundHandlerAdapter {

	public static final Logger log = LoggerFactory.getLogger(ObjClientHandler.class);
	
	int counter = 0;
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		Dept dept = new Dept("Hel", "Hello world!");
		ctx.writeAndFlush(dept);
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		log.info("this is " + ++counter + " times receive server [" + msg.toString() + "]");
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}

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

3.4 ObjClient

public class ObjClient {
	public static final Logger log = LoggerFactory.getLogger(ObjClient.class);

	public void connect(int port, String host) throws InterruptedException {
		EventLoopGroup group = new NioEventLoopGroup();
		
		Bootstrap bootstrap = new Bootstrap();
		bootstrap.group(group)
		    .channel(NioSocketChannel.class)
		    .option(ChannelOption.TCP_NODELAY, true)
		    .handler(new ChannelInitializer<NioSocketChannel>() {
		    	@Override
	            protected void initChannel(NioSocketChannel ch) throws Exception {
	                final ChannelPipeline pipeline = ch.pipeline();
	                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
	                // 客户端编码要发送的java对象
	                pipeline.addLast(new ObjectEncoder());
	                // 客户端解码接收的java对象码流
	                pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(ClassLoader.getSystemClassLoader())));
	                pipeline.addLast(new ObjClientHandler());
	            }
		    });
		
		ChannelFuture future = bootstrap.connect(host, port).sync();
		
		future.channel().closeFuture().sync();
	}
	
	public static void main(String[] args) throws InterruptedException {
		new ObjClient().connect(8001, "127.0.0.1");
	}
}

3.5 Dept序列化对象

public class Dept implements java.io.Serializable {

	private static final long serialVersionUID = 4663236112565339000L;
	
	public static final Logger log = LoggerFactory.getLogger(Dept.class);

	private String deptName;
	
	private String deptRemark;
	
	public Dept(String deptName, String deptRemark) {
		this.deptName = deptName;
		this.deptRemark = deptRemark;
	}

	public String getDeptName() {
		return deptName;
	}

	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}

	public String getDeptRemark() {
		return deptRemark;
	}

	public void setDeptRemark(String deptRemark) {
		this.deptRemark = deptRemark;
	}
	
	@Override
	public String toString() {
		return "deptName: "+deptName+", deptRemark: "+deptRemark;
	}
}

3.6 服务端日志

  • 读取数据日志
    在这里插入图片描述

服务端读取到58字节。
日志打印数据用16进制展示ascii码。
"Hello world!"数据的十进制和十六进制对应关系如下表。

Helloworld!
Hex48656c6c6f20776f726c6421
Dec721011081081113211911111410810033

3.7 客户端日志

  • 发送数据日志
    在这里插入图片描述
  • 接收数据日志
    在这里插入图片描述

4. 总结

同样的java object,在上一篇文章中使用java 序列化码流大小为117字节,使用netty自带的码流为58字节,只看体积就可以看出是有差距的。当传输数据量比较大的时候,编码后的字节数组越大,存储的时候越占空间,存储的硬件成本响应变高,网络传输时更占带宽,系统的存储量就降低。所以相比较而言,Java序列化方式在码流大小方面局限性还是有的。

参照上一篇:Netty框架编解码之Java序列化码流测量

标签:码流,Netty,netty,编解码,void,io,import,new,public
来源: https://blog.csdn.net/lzx5290/article/details/120659638

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有