一起学netty(18)netty整合protobuf实现高性能数据传输
之前的文章介绍了protobuf的概念参考:http://www.jiajiajia.club/blog/artical/351psy9r6l0g/464
以及protobuf的编码方式参考:http://www.jiajiajia.club/blog/artical/5puo1goygd3o/463
proto文件准备
Animal.proto
syntax = "proto3";
import "Dog.proto";
import "Cat.proto";
option java_package = "com.weblog.netty.proto.file";
option java_outer_classname="Animal";
message AnimalInfo{
enum AnimalType {
HEARTBEAT = 0;
DOG = 1;
CAT = 2;
}
AnimalType animalType = 1;
oneof dataBody{
DogInfo dog = 2;
CatInfo cat = 3;
}
Cat.proto
syntax = "proto3";
option java_package = "com.weblog.netty.proto.file";
option java_outer_classname="Cat";
message CatInfo{
string catName = 1;
int32 age = 2;
}
Dog.proto
syntax = "proto3";
option java_package = "com.weblog.netty.proto.file";
option java_outer_classname="Dog";
message DogInfo{
string dogName = 1;
int32 age = 2;
}
生成java类的命令 protoc -I=./ --java_out=./ ./Animal.proto
,或参考之前的文章。
整体目录:

生成的代码太长了,就不贴出了来了。
服务端代码:
import com.weblog.netty.websocket.server.entity.Animal;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyServerProtobuf {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup bootGroup = new NioEventLoopGroup(1);
NioEventLoopGroup work = new NioEventLoopGroup(8);
ServerBootstrap boot = new ServerBootstrap();
boot.channel(NioServerSocketChannel.class)
.group(bootGroup,work)
.childHandler(new ChannelInitializer(){
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
// String编码器
pipeline.addLast(new StringEncoder());
// protobuf解码器
pipeline.addLast(new ProtobufDecoder(Animal.AnimalInfo.getDefaultInstance()));
// 自定义处理器
pipeline.addLast(new SimpleChannelInboundHandler<Animal.AnimalInfo>(){
@Override
public void channelRead0(ChannelHandlerContext ctx, Animal.AnimalInfo msg) throws Exception {
// 打印客户端发送的数据
System.out.println(msg);
// 服务器端向客户端回写数据,使用的是字符串类型的编码器
ctx.writeAndFlush("收到");
ctx.fireChannelActive();
}
});
}
});
ChannelFuture sync = boot.bind(8100).sync();
sync.channel().closeFuture().sync();
}
}
客户端代码
import com.weblog.netty.websocket.server.entity.Animal;
import com.weblog.netty.websocket.server.entity.Dog;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.string.StringDecoder;
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup bootGroup = new NioEventLoopGroup(1);
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(bootGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// protobuf编码器
pipeline.addLast(new ProtobufEncoder());
// String解码器
pipeline.addLast(new StringDecoder());
// 自定义处理器
pipeline.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(msg);
}
});
}
});
ChannelFuture future = bootstrap.connect("localhost", 8100).sync();
Channel channel = future.channel();
// 构造需要发送的数据
Animal.AnimalInfo.Builder animal = Animal.AnimalInfo.newBuilder();
animal.setAnimalType(Animal.AnimalInfo.AnimalType.DOG);
Dog.DogInfo.Builder dog = Dog.DogInfo.newBuilder();
dog.setAge(1);
dog.setDogName("小花");
animal.setDog(dog);
// 发送数据
channel.writeAndFlush(animal);
ChannelFuture future1 = channel.closeFuture().sync();
}
}
客户端向服务端发送数据使用的是protobuf
编码,服务端向客户端发送数据是字符串,所以客户端的编码器是ProtobufEncoder
解码器是StringDecoder
,服务端的解码器是ProtobufDecoder
编码器是StringEncoder
。
服务端先启动,客户端启动后服务端打印:
animalType: DOG
dog {
dogName: "\345\260\217\350\212\261"
age: 1
}
客户端打印:
收到
fixed
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。