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可以处理半包消息