<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Netty 使用 Protobuf 序列化,真香!

          共 11577字,需瀏覽 24分鐘

           ·

          2021-06-17 22:39

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          作者:rickiyang
          出處:www.cnblogs.com/rickiyang/p/11074232.html

          我們來使用Protobuf進(jìn)行序列化,它和XML,json一樣都有自己的語法,xml的后綴是.xml,json文件的后綴是.json,自然Protobuf文件的后綴就是.proto(哈哈,當(dāng)然不是全稱)。

          下面我們使用Protobuf來封裝一段消息,通過一個(gè)案例簡(jiǎn)單介紹一下它的使用。

          首先我們用Protobuf的語法格式來寫一段需要序列化的對(duì)象,命名格式為: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;
          }

          關(guān)于Message.proto中的語法格式,詳情大家google一下相關(guān)的說明,網(wǎng)上很多介紹,再次簡(jiǎn)單就上面的語法說明一下:

          • option java_package:表示生成的.java文件的包名
          • option java_outer_classname:生成的java文件的文件名
          • message :為他的基本類型,如同java中的class一樣

          字段修飾符:

          • required:一個(gè)格式良好的消息一定要含有1個(gè)這種字段。表示該值是必須要設(shè)置的;
          • optional:消息格式中該字段可以有0個(gè)或1個(gè)值(不超過1個(gè))。
          • repeated:在一個(gè)格式良好的消息中,這種字段可以重復(fù)任意多次(包括0次)。重復(fù)的值的順序會(huì)被保留。表示該值可以重復(fù),相當(dāng)于java中的List。

          字符類型稍微有些不同:double,float,int32,int64,bool(boolean),string,bytes。稍微有些不同,String,boolean,int有差別。

          另外我們看到上面3個(gè)字段分別賦值了,這個(gè)值是什么意思呢?消息定義中,每個(gè)字段都有唯一的一個(gè)數(shù)字標(biāo)識(shí)符。這些標(biāo)識(shí)符是用來在消息的二進(jìn)制格式中識(shí)別各個(gè)字段的,一旦開始使用就不能夠再改變。注:[1,15]之內(nèi)的標(biāo)識(shí)號(hào)在編碼的時(shí)候會(huì)占用一個(gè)字節(jié)。[16,2047]之內(nèi)的標(biāo)識(shí)號(hào)則占用2個(gè)字節(jié)。所以應(yīng)該為那些頻繁出現(xiàn)的消息元素保留 [1,15]之內(nèi)的標(biāo)識(shí)號(hào)。

          關(guān)于Protobuf 的語法我們就簡(jiǎn)單的介紹這么多,更多細(xì)節(jié)大家自己去查閱文檔吧。下面我們開始使用Protobuf 來進(jìn)行序列化。Spring Boot 學(xué)習(xí)筆記這個(gè)分享給你。

          首先我們的在工程中引入protobuf的jar包,目前官方版本最高3.2,我們用3.0的吧:

          <dependency>
              <groupId>com.google.protobuf</groupId>
              <artifactId>protobuf-java</artifactId>
              <version>3.0.2</version>
          </dependency>

          Protobuf的文件已經(jīng)定義好了,下就需要把它編譯成java代碼,這里我們的借助到google為我們提供的腳本工具protoc,鏈接在這里,點(diǎn)擊下載這里提供的是protoc-3.0.2。

          要注意protoc的版本需要和Protobuf的版本對(duì)應(yīng)上,不然不同的版本之間會(huì)有一些差異解析可能會(huì)有問題。現(xiàn)在知道我們?yōu)樯斗堑眠x用protobuf3.0.2版本吧,因?yàn)槲覜]有找到別的版本的protoc。。。

          下載好了我們解壓縮然后把剛才寫好的Msg.proto文件復(fù)制進(jìn)去。

          接著我們進(jìn)cmd輸入如下命令:

          主要是第三句命令。如果你輸入沒有報(bào)錯(cuò)的話你的proto文件夾應(yīng)該會(huì)生成一個(gè)子文件夾:

          進(jìn)去該文件夾你會(huì)看到已經(jīng)生成了MessageProto.java文件,恭喜你,這時(shí)候你已經(jīng)完成了protobuf序列化文件的生成。然后你把該文件拷貝至工程目錄下。

          接下來我們用生成的文件去發(fā)消息吧。還是老套路服務(wù)端和客戶端。另外,微信搜索Java技術(shù)棧,在后臺(tái)回復(fù):面試,可以獲取我整理的 Java 系列面試題和答案,非常齊全。

          服務(wù)端:

          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();
              }
          }

          服務(wù)端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());
              }
          }

          服務(wù)端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");
              }
          }

          啟動(dòng)服務(wù)端和客戶端,輸出如下:

          最簡(jiǎn)單的protoBuf應(yīng)用案例我們就寫完了,真實(shí)的使用場(chǎng)景大同小異,隨機(jī)應(yīng)變即可。另外,關(guān)注公眾號(hào)Java技術(shù)棧,在后臺(tái)回復(fù):面試,可以獲取我整理的 Java 系列面試題和答案,非常齊全。






          關(guān)注Java技術(shù)??锤喔韶?/strong>



          獲取 Spring Boot 實(shí)戰(zhàn)筆記!
          瀏覽 43
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级黄色电影在线免费观看 | 一级片在线视频播放 | 内射极品在线观看免费 | 国产人妖TS重口系列91中文 | 亚洲成人大片 |