在netty的数据传输中,客户端和服务端只能同时有一种协议生效,而在proto文件中却可能会存在定义多个message,那么就需要我们通过枚举的方式去实现多协议的传递方式。
如下是proto文件的定义方式
Person.proto
syntax="proto2";
//文件特性
package com.test.protobuf;
option optimize_for = SPEED; //加快解析速度 默认是SPEED
option java_package = "com.netty.sixth";
option java_outer_classname = "MyDateInto";
message MyMessage{
enum DataType{
PersonType = 1;
DogType = 2;
CatType = 3;
}
required DataType data_type = 1;
//oneof 数据体
oneof dataBody{
Person person = 2;
Dog dog = 3;
Cat cat = 4;
}
}
message Person{
optional string name = 1;
optional int32 age = 2;
optional string address = 3;
}
message Dog{
optional string name=1;
optional int32 age=2;
}
message Cat{
optional string name=1;
optional string city=2;
}
执行protoc操作会生成对应的class MyDataInfo
服务端代码:
TestServer.java
public class TestServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new TestServerInitializer());
ChannelFuture channelFuture = bootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
TestServerInitializer.java
public class TestServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//netty 提供了四个处理器进行protobuf的编解码处理
pipeline.addLast(new ProtobufVarint32FrameDecoder());
//ProtobufDecoder解码器:将字节数组转换成对象 参数就是要转换的类的实例
pipeline.addLast(new ProtobufDecoder(MyDateInto.MyMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestServerHandler());
}
}
TestServerHandler.java
//数据传递类型为协议最顶层的message
public class TestServerHandler extends SimpleChannelInboundHandler<MyDateInto.MyMessage> {
@Override
//此时过来的时候就已经被netty的handler处理了
protected void channelRead0(ChannelHandlerContext ctx, MyDateInto.MyMessage msg) throws Exception {
//对接收到的对象进行处理
MyDateInto.MyMessage.DataType dataType = msg.getDataType();
if(dataType == MyDateInto.MyMessage.DataType.PersonType){
MyDateInto.Person person = msg.getPerson();
System.out.println(person.getName());
System.out.println(person.getAge());
System.out.println(person.getAddress());
}else if (dataType == MyDateInto.MyMessage.DataType.DogType){
MyDateInto.Dog dog = msg.getDog();
System.out.println(dog.getName());
System.out.println(dog.getAge());
}else{
MyDateInto.Cat cat = msg.getCat();
System.out.println(cat.getName());
System.out.println(cat.getCity());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端代码
TestClient.java
public class TestClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new TestClientInitializer());
Channel channel = bootstrap.connect("localhost",8899).sync().channel();
channel.closeFuture().sync();
}finally {
eventLoopGroup.shutdownGracefully();
}
}
}
TestClientInitializer.java
public class TestClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufDecoder(MyDateInto.MyMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestClientHandler());
}
}
TestClientHandler.java
public class TestClientHandler extends SimpleChannelInboundHandler<MyDateInto.MyMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyDateInto.MyMessage msg) throws Exception {
System.out.println(msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
int randomInt = new Random().nextInt(3); //0,1,2
MyDateInto.MyMessage myMessage = null;
//构造对象
if (0 == randomInt){
myMessage = MyDateInto.MyMessage.newBuilder().
setDataType(MyDateInto.MyMessage.DataType.PersonType).
setPerson(MyDateInto.Person.newBuilder().setName("张三")
.setAge(25).setAddress("湖南").build()).build();
}else if (1== randomInt){
myMessage = MyDateInto.MyMessage.newBuilder().
setDataType(MyDateInto.MyMessage.DataType.DogType).
setDog(MyDateInto.Dog.newBuilder().setName("德牧")
.setAge(25).build()).build();
}else{
myMessage = MyDateInto.MyMessage.newBuilder().
setDataType(MyDateInto.MyMessage.DataType.CatType).
setCat(MyDateInto.Cat.newBuilder().setName("龙猫")
.setCity("西班牙").build()).build();
}
ctx.writeAndFlush(myMessage);
}
}