ProtoBuf
解释
ProtoBuf是谷歌提供的一种轻便高效的结构化数据存储格式.它很适合做数据存储以及RPC远程调用数据交换
为什么需要ProtoBuf
编写网络应用程序时,数据在网络中传输的都是二进制字节码数据。在发送时需要编码,接收时需要解码。netty本身自带的ObjectEncoder和ObjectDecoder可以实现各种业务对象的编解码操作,但是底层依然使用的是java序列化技术,效率不高,序列化后体积过大,并且无法跨语言,所以可以使用protoBuf来解决。目前大多数公司使用方法是Http+Json Tcp+ProtoBuf
快速入门
编写一个最简单的User.proto文件
syntax = "proto3"; //proto版本
option java_outer_classname="UserPOJO"; //生成java文件名
message User{
int32 id = 1;
string name = 2;
}
下载protoc的jar,在bin目录下打开cmd,把刚才编写的User.proto复制到该目录下,运行命令 protoc.exe --java_out=. User.proto 即可生成一个对应的UserPOJO
使用UserPOJO来实现服务器端和客户端通信并编解码
服务器端
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
public class ProtoServer {
public static void main(String[] args) {
EventLoopGroup bs = new NioEventLoopGroup(1);
EventLoopGroup wk = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bs,wk).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,127)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//netty提供的proto解码器
pipeline.addLast(new ProtobufDecoder(UserPOJO.User.getDefaultInstance()));
pipeline.addLast(new ProtoServerHandler());
}
});
ChannelFuture future = serverBootstrap.bind(8555).sync();
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bs.shutdownGracefully();
wk.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ProtoServerHandler extends SimpleChannelInboundHandler<UserPOJO.User> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, UserPOJO.User user) throws Exception {
System.out.println("读取到数据"+user.getId()+"----------------"+user.getName());
}
}
客户端
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
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;
public class ProtoClient {
public static void main(String[] args) {
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//netty提供的编码器
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new ProtoClientHandler());
}
});
ChannelFuture future = bootstrap.connect("127.0.0.1", 8555).sync();
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
eventExecutors.shutdownGracefully();
}
}
}
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ProtoClientHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
UserPOJO.User.Builder builder = UserPOJO.User.newBuilder();
builder.setId(10);
builder.setName("张三");
channel.writeAndFlush(builder);
}
}
启动项目测试