作者:rickiyang
出处:www.cnblogs.com/rickiyang/p/11074232.html
咱们来应用Protobuf进行序列化,它和XML,json一样都有本人的语法,xml的后缀是.xml,json文件的后缀是.json,天然Protobuf文件的后缀就是.proto(哈哈,当然不是全称)。
上面咱们应用Protobuf来封装一段音讯,通过一个案例简略介绍一下它的应用。
首先咱们用Protobuf的语法格局来写一段须要序列化的对象,命名格局为:Msg.proto
option java_package = "cn.edu.hust.netty.demo10";option java_outer_classname = "MessageProto";message RequestMsg{ required bytes msgType = 1; required string receiveOne = 2; required string msg = 3;}message ResponseMsg{ required bytes msgType = 1; required string receiveOne = 2; required string msg = 3;}
对于Message.proto中的语法格局,详情大家google一下相干的阐明,网上很多介绍,再次简略就下面的语法阐明一下:
- option java_package:示意生成的.java文件的包名
- option java_outer_classname:生成的java文件的文件名
- message : 为他的根本类型,如同java中的class一样
字段修饰符:
- required:一个格局良好的音讯肯定要含有1个这种字段。示意该值是必须要设置的;
- optional:音讯格局中该字段能够有0个或1个值(不超过1个)。
- repeated:在一个格局良好的音讯中,这种字段能够反复任意屡次(包含0次)。反复的值的程序会被保留。示意该值能够反复,相当于java中的List。
字符类型略微有些不同:double,float,int32,int64,bool(boolean),string,bytes。略微有些不同,String,boolean,int有差异。
另外咱们看到下面3个字段别离赋值了,这个值是什么意思呢?音讯定义中,每个字段都有惟一的一个数字标识符。这些标识符是用来在音讯的二进制格局中辨认各个字段的,一旦开始应用就不可能再扭转。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁呈现的音讯元素保留 [1,15]之内的标识号。
对于Protobuf 的语法咱们就简略的介绍这么多,更多细节大家本人去查阅文档吧。上面咱们开始应用Protobuf 来进行序列化。
首先咱们的在工程中引入protobuf的jar包,目前官网版本最高3.2,咱们用3.0的吧:
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.0.2</version></dependency>
Protobuf的文件曾经定义好了,下就须要把它编译成java代码,这里咱们的借助到google为咱们提供的脚本工具protoc,链接在这里,点击下载这里提供的是protoc-3.0.2。要留神protoc的版本须要和Protobuf的版本对应上,不然不同的版本之间会有一些差别解析可能会有问题。当初晓得咱们为啥非得选用protobuf3.0.2版本吧,因为我没有找到别的版本的protoc。。。
下载好了咱们解压缩而后把方才写好的Msg.proto文件复制进去。
接着咱们进cmd输出如下命令:
次要是第三句命令。如果你输出没有报错的话你的proto文件夹应该会生成一个子文件夹:
进去该文件夹你会看到曾经生成了MessageProto.java文件,祝贺你,这时候你曾经实现了protobuf序列化文件的生成。而后你把该文件拷贝至工程目录下。
接下来咱们用生成的文件去发消息吧。还是老套路服务端和客户端。
服务端:
public class ProtoBufServer { private int port; public ProtoBufServer(int port) { this.port = port; } public void start(){ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workGroup = new NioEventLoopGroup(); ServerBootstrap server = new ServerBootstrap().group(bossGroup,workGroup) .channel(NioServerSocketChannel.class) .childHandler(new ServerChannelInitializer()); try { ChannelFuture future = server.bind(port).sync(); future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { bossGroup.shutdownGracefully(); workGroup.shutdownGracefully(); } } public static void main(String[] args) { ProtoBufServer server = new ProtoBufServer(7788); server.start(); }}
服务端Initializer:
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new ProtobufVarint32FrameDecoder()); pipeline.addLast(new ProtobufDecoder(MessageProto.RequestMsg.getDefaultInstance())); pipeline.addLast(new ProtoBufServerHandler()); }}
服务端handler:
public class ProtoBufServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { MessageProto.ResponseMsg.Builder builder = MessageProto.ResponseMsg.newBuilder(); builder.setMsgType(ByteString.copyFromUtf8("CBSP")); builder.setReceiveOne("小红"); builder.setMsg("你好,你有啥事"); ctx.writeAndFlush(builder.build()); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { MessageProto.RequestMsg m = (MessageProto.RequestMsg)msg; System.out.println("Client say: "+m.getReceiveOne()+","+m.getMsg()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); ctx.close(); }}
客户端:
public class ProtoBufClient { private int port; private String address; public ProtoBufClient(int port, String address) { this.port = port; this.address = address; } public void start(){ EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ClientChannelInitializer()); try { ChannelFuture future = bootstrap.connect(address,port).sync(); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); }finally { group.shutdownGracefully(); } } public static void main(String[] args) { ProtoBufClient client = new ProtoBufClient(7788,"127.0.0.1"); client.start(); }}
客户端Initializer:
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> { protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast(new ProtobufEncoder()); pipeline.addLast(new ProtoBufClientHandler()); }}客户端handler:public class ProtoBufClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { MessageProto.ResponseMsg m = (MessageProto.ResponseMsg)msg; System.out.println("Server say: "+m.getReceiveOne()+","+m.getMsg()); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { MessageProto.RequestMsg.Builder builder = MessageProto.RequestMsg.newBuilder(); builder.setMsgType(ByteString.copyFromUtf8("CBSP")); builder.setReceiveOne("小明"); builder.setMsg("你好,我找你有事"); ctx.writeAndFlush(builder.build()); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println("Client is close"); }}
启动服务端和客户端,输入如下:
最简略的protoBuf利用案例咱们就写完了,实在的应用场景大同小异,随机应变即可。
近期热文举荐:
1.1,000+ 道 Java面试题及答案整顿(2021最新版)
2.终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!
3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!