Java的序列化和反序列化性能是很低的,序列化后的字节流大,无法跨语言。一些主流的编解码器性能可观,得到了广泛的认可,如 Marshaling、Protobuf、MessagePack等,Netty对主流的编解码器都有实现,我们看下其中的一个Protobuf是怎么使用的。
生成java文件
下载文件
定义.proto文件
我们这里定义两个文件
syntax = "proto3";
message SearchReq {
string name = 1;
int32 age = 2;
}
syntax = "proto3";
message SearchResp {
string name = 1;
int32 age = 2;
}
执行命令生成文件
Netty 使用Protobuf
将生成的类拷贝到项目中
添加protobuf依赖
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>4.29.1</version>
</dependency>
NettyServer
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new ProtobufVarint32FrameDecoder());
socketChannel.pipeline().addLast(new ProtobufDecoder(SearchReqOuterClass.SearchReq.getDefaultInstance()));
socketChannel.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
socketChannel.pipeline().addLast(new ProtobufEncoder());
socketChannel.pipeline().addLast(new NIOServerHandler());
}
});
ChannelFuture sync = bootstrap.bind(new InetSocketAddress(8080)).sync();
sync.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
NIOServerHandler
public class NIOServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收客户端的数据
SearchReqOuterClass.SearchReq message = (SearchReqOuterClass.SearchReq) msg;
System.out.println("服务端接收到客户端的消息:" + message.toString());
//响应给客户端
SearchRespOuterClass.SearchResp.Builder builder = SearchRespOuterClass.SearchResp.newBuilder();
builder.setAge(100);
builder.setName("响应给客户端的数据");
SearchRespOuterClass.SearchResp build = builder.build();
ctx.writeAndFlush(build);
}
}
NettyClient
public class NettyClient {
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
try {
Bootstrap handler = bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(new ProtobufDecoder(SearchRespOuterClass.SearchResp.getDefaultInstance()));
ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new NioClientHandler());
}
});
ChannelFuture sync = handler.connect(new InetSocketAddress("127.0.0.1", 8080)).sync();
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
group.shutdownGracefully();
}
}
}
NioClientHandler
public class NioClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//发送数据给服务器
SearchReqOuterClass.SearchReq.Builder builder = SearchReqOuterClass.SearchReq.newBuilder();
builder.setName("给服务器的数据");
builder.setAge(100);
SearchReqOuterClass.SearchReq searchReq = builder.build();
ctx.writeAndFlush(searchReq);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
SearchRespOuterClass.SearchResp searchResp = (SearchRespOuterClass.SearchResp) msg;
System.out.println("接收来自服务器数据:" + searchResp.toString());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}