Netty的入门-编解码技术

Java序列化:

实现Serializable接口即可,方便但是缺点很多:1、java私有协议,无法跨语言;2、序列化后的码流太大;3、序列化性能低

Server ChannelPipeLine中添加ObjectDecoder,Client ChannelPipeline中添加ObjectEncoder,对象实现Serializable接口。

ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
				.channel(NioServerSocketChannel.class)
				.option(ChannelOption.SO_BACKLOG, 100)
				.handler(new LoggingHandler(LogLevel.INFO))
				.childHandler(new ChannelInitializer<SocketChannel>() {

					@Override
					protected void initChannel(SocketChannel ch)
							throws Exception {
						ch.pipeline().addLast(
								new ObjectDecoder(
										1024*1024,
										ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
						ch.pipeline().addLast(new ObjectEncoder());
						ch.pipeline().addLast(new SubReqServerHandler());
						
					}
				});
			ChannelFuture f = b.bind(port).sync();
			f.channel().closeFuture().sync();
Bootstrap b = new Bootstrap();
			b.group(group)
				.option(ChannelOption.TCP_NODELAY, true)
				.handler(new LoggingHandler(LogLevel.INFO))
				.channel(NioSocketChannel.class)
				.handler(new ChannelInitializer<SocketChannel>() {

					@Override
					protected void initChannel(SocketChannel ch)
							throws Exception {
						// 动态模块化编程,很少对类加载器进行缓存
						ch.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
						ch.pipeline().addLast(new ObjectEncoder());
						ch.pipeline().addLast(new SubReqClientHandler());
					}
				});
			ChannelFuture f = b.connect(host, port).sync();
			f.channel().closeFuture().sync();

Google的Protobuf

Protocol Buffer跨语言,支持C++,Java和Python;编解码性能高,码流小;支持必选和可选字段。

protoc.exe工具主要是对.proto文件生成代码,使用方法:protoc.exe --java_out=.\src .\netty\SubscribeReq.proto

package netty;
option java_package = "com.eric.samples.demo7";
option java_outer_classname = "SubscribeReqProto";

message SubscribeReq {
	required int32 subReqID = 1;
	required string userName = 2;
	required string productName = 3;
	repeated string address = 4;
}

package netty;
option java_package = "com.eric.samples.demo7";
option java_outer_classname = "SubscribeRespProto";

message SubscribeResp {
	required int32 subReqID = 1;
	required string userName = 2;
	required string desc = 3;
}


public class ProtoBuffTest {

	public static void main(String[] args) throws InvalidProtocolBufferException {
		SubscribeReq req = createSubscribeReq();
		System.out.println("before encode: " + req.toString());
		SubscribeReq req2 = decode(encode(req));
		System.out.println("after decode: " + req2.toString());
		System.out.println("assert: " + req.equals(req2));
	}
	
	public static SubscribeReq decode(byte[] body) throws InvalidProtocolBufferException {
		return SubscribeReq.parseFrom(body);
	}
	
	public static byte[] encode(SubscribeReq req) {
		return req.toByteArray();
	}
	
	public static SubscribeReq createSubscribeReq() {
		Builder builder = SubscribeReq.newBuilder();
		builder.setSubReqID(1);
		builder.setUserName("lanou");
		builder.setProductName("computer");
		List<String> address = new ArrayList<String>();
		address.add("aaaa");
		address.add("bbbb");
		address.add("cccc");
		address.add("dddd");
		builder.addAllAddress(address);
		return builder.build();
	}

}

ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
				.channel(NioServerSocketChannel.class)
				.option(ChannelOption.SO_BACKLOG, 100)
				.handler(new LoggingHandler(LogLevel.INFO))
				.childHandler(new ChannelInitializer<SocketChannel>() {

					@Override
					protected void initChannel(SocketChannel ch)
							throws Exception {
						ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
						ch.pipeline().addLast(new ProtobufDecoder(SubscribeReq.getDefaultInstance()));
						ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
						ch.pipeline().addLast(new ProtobufEncoder());
						ch.pipeline().addLast(new SubReqServerHandler());
					}
				});
			ChannelFuture f = b.bind(port).sync();
			f.channel().closeFuture().sync();

Bootstrap b = new Bootstrap();
			b.group(group)
				.option(ChannelOption.TCP_NODELAY, true)
				.handler(new LoggingHandler(LogLevel.INFO))
				.channel(NioSocketChannel.class)
				.handler(new ChannelInitializer<SocketChannel>() {

					@Override
					protected void initChannel(SocketChannel ch)
							throws Exception {
						ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
						ch.pipeline().addLast(new ProtobufDecoder(SubscribeResp.getDefaultInstance()));
						ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
						ch.pipeline().addLast(new ProtobufEncoder());
						ch.pipeline().addLast(new SubReqClientHandler());
					}
				});
			ChannelFuture f = b.connect(host, port).sync();
			f.channel().closeFuture().sync();

使用protobuf的注意事项:

1、ProtobufDecoder仅仅负责编码,不支持读半包

2、使用Netty提供的ProtobufVarint32FrameDecoder可以处理半包消息




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值