解决方案有2中:
第一种:官方列子中提到的自定义协议的方式,该方式比较繁琐且没有使用protobuf的任何特性
第二种:使用protobuf的one of 来定义共享空间的方式来解决protobuf不支持多协议的问题
本文使用使用第二种方式实现:
1. 编写.proto文件
syntax = "proto2";
package com.baidu.com.netty.protobuf;
option java_package = "com.baidu.com.netty.protobuf";
option java_outer_classname = "PersonData";
option optimize_for = SPEED;
message Person{
required string name = 1;
optional int32 age = 2;
optional bool marraied = 3;
}
message Teacher{
optional string name = 1;
optional float pay = 2;
}
message Student{
optional int64 id = 1;
optional string name = 2;
}
message Message{
enum DataType {
PERSON = 1;
TEACHER = 2;
STUDENT = 3;
}
required DataType type = 1 [default = PERSON];
oneof dataMsg {
Person person = 2;
Teacher teacher = 3;
Student stu = 4;
}
}
2. 使用protobuf的编译器生产对应的类
protoc --java_out= 生成的地址 proto文件存放的地址
3. 编写服务器端启动程序
package com.baidu.com.netty.protobuf;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class MyServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new MyServerInitializer());
ChannelFuture future = serverBootstrap.bind(8899).sync();
future.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
4. 编写服务器端初始化程序
package com.baidu.com.netty.protobuf;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
public class MyServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(PersonData.Message.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new MyServerHandler());
}
}
5. 编写服务器端处理程序
package com.baidu.com.netty.protobuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class MyServerHandler extends SimpleChannelInboundHandler<PersonData.Message> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, PersonData.Message msg) throws Exception {
if(msg.getType() == PersonData.Message.DataType.PERSON)
{
PersonData.Person person = msg.getPerson();
System.out.println(person.getName());
} else if (msg.getType() == PersonData.Message.DataType.TEACHER)
{
PersonData.Teacher teacher = msg.getTeacher();
System.out.println("我是一个老师,我叫: " + teacher.getName());
} else if(msg.getType() == PersonData.Message.DataType.STUDENT)
{
PersonData.Student student = msg.getStu();
System.out.println("我是一个学生,我叫: " + student.getName());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// cause.printStackTrace();
ctx.close();
}
}
6. 编写客户端启动程序和初始化程序
7. 编写客户端处理程序
package com.baidu.com.netty.protobuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.Random;
public class MyClientHandler extends SimpleChannelInboundHandler<PersonData.Message> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, PersonData.Message msg) throws Exception {
if (null != msg && msg.getType().equals(PersonData.Message.DataType.PERSON))
{
PersonData.Person person = msg.getPerson();
System.out.println(person.getName());
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
int index = new Random().nextInt(3);
System.out.println(index);
PersonData.Message data = null;
if(index == 0)
{
data = PersonData.Message.newBuilder().setType(PersonData.Message.DataType.PERSON).setPerson(PersonData.Person.newBuilder().setAge(10).setName("admin").build()).build();
}else if (index == 1)
{
data = PersonData.Message.newBuilder().setType(PersonData.Message.DataType.TEACHER).setTeacher(PersonData.Teacher.newBuilder().setName("老徐").build()).build();
}else if ((index == 2))
{
data = PersonData.Message.newBuilder().setType(PersonData.Message.DataType.STUDENT).setStu(PersonData.Student.newBuilder().setName("小学生").build()).build();
}
System.out.println(data);
System.out.println(ctx);
ctx.writeAndFlush(data);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// cause.printStackTrace();
ctx.close();
}
}