protobuf要先下载 需要翻墙不熟悉的可以看下官方文档的介绍
https://developers.google.com/protocol-buffers/
不能翻墙的可以在下面的地址下载
https://github.com/protocolbuffers/protobuf
syntax = "proto3";
message ClientMessage {
enum ClientType {
SearchRequestType = 0;
ShopRequestType = 1;
}
ClientType data_type = 1;
oneof dataBody {
SearchRequest searchRequest = 2;
ShopRequest shopRequest = 3;
}
}
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message ShopRequest {
string shopName = 1;
int64 shopType = 2;
}
使用下面的命令可以生成Java代码
protoc --java_out=./ message.proto
/**
* protobuf Google在维护
* 1 支持跨语言
* 2 编码后消息小(相比Java的序列化)有利于网络的传出
* 3 .proto文件可读性好
*/
public class TestProtobuf {
public static void main(String[] args) throws InvalidProtocolBufferException {
//链式调用构建
Message.SearchRequest build = Message.SearchRequest.newBuilder().setPageNumber(1).setQuery("34").build();
//获取编码数组序列化
byte[] bytes = build.toByteArray();
//解析获取反序列化
Message.SearchRequest searchRequest = Message.SearchRequest.parseFrom(bytes);
System.out.println(build);
System.out.println(searchRequest);
System.out.println(build.equals(searchRequest));
System.out.println(build == searchRequest);
}
}
用netty传输的客户端代码
/**
* protobuf的客户端
*/
public class Client {
public static void main(String[] args) {
//事件循环组
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
//客户端的启动
Bootstrap bootstrap = new Bootstrap();
//处理事件,反射创建channel实例,处理的handler
bootstrap.group(eventExecutors).channel(NioSocketChannel.class).
handler(new ClientProtobufInitializer());
//绑定端口号
ChannelFuture channelFuture = bootstrap.connect("localhost", 8090).sync();
//关闭通道
ChannelFuture channelFuture1 = channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//异常发生退出
eventExecutors.shutdownGracefully();
}
}
}
public class ClientProtobufInitializer extends ChannelInitializer <SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//protobuf仅仅负责解码不支持读半包所以可以用Netty提供的
//1ProtobufVarint32FrameDecoder处理
//继承LengthFieldBasedFrameDecoder
//继承btyeToMessageDecoder类自己处理
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(Message.ClientMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestProtobufClientHandle());
}
}
public class TestProtobufClientHandle extends SimpleChannelInboundHandler <Message.ClientMessage> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Message.ClientMessage build = Message.ClientMessage.newBuilder().
setDataType(Message.ClientMessage.ClientType.SearchRequestType).
setSearchRequest(Message.SearchRequest.
newBuilder().
setQuery("query").
setPageNumber(1).
build())
.build();
ctx.channel().writeAndFlush(build);
super.channelActive(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Message.ClientMessage msg) throws Exception {
}
}
服务器代码
public class Server {
public static void main(String[] args) {
//事件循环组,boos负责接受
EventLoopGroup boosGroup = new NioEventLoopGroup();
//worker负责处理boss接受的信息
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//启动设置引导
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boosGroup, workerGroup).channel(NioServerSocketChannel.class).
// 定义的自动初始化管道
childHandler(new ProtobufInitalizer());
//绑定端口
ChannelFuture channelFuture = serverBootstrap.bind(8090).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
//事件循环优雅的退出
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class ProtobufInitalizer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(Message.ClientMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestProtobufHandle());
}
}
public class TestProtobufHandle extends SimpleChannelInboundHandler <Message.ClientMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Message.ClientMessage msg) throws Exception {
Message.ClientMessage.ClientType dataType = msg.getDataType();
if (Message.ClientMessage.ClientType.SearchRequestType.equals(dataType)) {
System.out.println(msg);
}
}
}