编码和解码的基本介绍

  1. 编写网络应用程序时, 因为数据在网络中传输的都是二进制字节码数据, 在发送数据时就需要编码, 接收数据时就需要解码
  2. codec(编解码器) 的组成部分有两个 : decoder(解码器)和encoder(编码器). encoder负责把业务数据转换成字节码数据, decoder负责把字节码数据转换成业务数据

Netty 本身的编解码的机制和问题分析

  1. Netty自身提供了一些codec(编解码器)
  2. Netty提供的编码器
    1. StringEncoder, 对字符串数据进行编码
    2. ObjectEncoder, 对Java对象进行编码
    1. ......
  1. Netty提供的解码器
    1. StringDecoder: 对字符串数据进行解码
    2. ObjectDecoder: 对Java对象进行解码
    1. ......
  1. Netty本身自带的ObjectDecoder和ObjectEncoder可以用来实现Pojo对象或各种业务对象的编码和解码,底层使用的依然是Java序列化技术, 而Java序列化技术本身效率就不高, 存在如下问题
    1. 无法跨语言
    2. 序列化后的体积太大, 是二进制编码的5倍多
    1. 序列化性能太低
  1. => 引出新的解决方案[Google 的 ProtoBuf]

Protobuf

  1. Protobuf基本介绍和使用示意图
  2. Protobuf是Google发布的开源项目, 全称 Google Protocol Buffers ,是一种 轻便高效的结构化数据存储格式,可以用于结构化数据串行化, 或者说序列化, 它很适合做数据存储或者RPC[远程过程调用]数据交换格式
    1. 目前很多公司 http + JSON -> tcp + protobuf
  1. 参考文档: https://developers.google.com/protocol-buffers/docs/proto 语言指南
  2. Protobuf是以message的方式来管理数据的
  1. 支持跨平台, 跨语言, 即[客户端和服务器端可以是不同的语言编写的] (支持目前绝大多数语言, 例如C++, C#, Java, Python等)
  2. 高性能, 高可靠性
  1. 使用Protobuf编译器能自动生成代码, Protobuf是将类的定义使用.proto文件进行描述, 说明, 在IDEA中编写.proto文件时, 会自动提示是否下载 .proto编写插件, 可以让语法高亮
  2. 然后通过protoc.exe编译器根据.proto自动生成.java文件
  1. Protobuf使用示意图

Protobuf快速入门案例

编写程序, 使用Protobuf完成如下功能

  1. 客户端可以发送一个Student POJO对象到服务器(通过Protobuf编码)
  2. 服务器能接受Student POJO对象, 并显示信息(通过Protobuf解码)

引入Protobuf的依赖

<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.6.1</version>
</dependency>

数据类型

特殊字段

定义其他复杂类型参考:https://blog.csdn.net/lijingjingchn/article/details/89466437

软件

新建Student.proto

syntax = "proto3"; // 版本
option java_outer_classname = "StudentPOJO"; // Java的外部类名
// protobuf 使用message 管理数据
message Student { // 会在 StudentPOJO外部类中生成一个内部类 Student, 它是真正发送的POJO对象/**表示 在Student类中有一个属性名字为 id , 类型为int32(Protobuf类型) 1表示序号, 不是值*/int32 id = 1;string name = 2;
}

根据.proto文件生成Java文件

将写好的文件放入bin文件夹中

在当前位置启动cmd

执行编译

protoc.exe --java_out=. Student.proto

将生成的文件拷贝到项目中

生成后的文件

不粘贴了[太大了],自己看一下吧

新建NettyServer

package com.dance.netty.netty.protobuf;import com.dance.netty.netty.protobuf.pojo.StudentPOJO;
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 NettyServer {public static void main(String[] args) throws InterruptedException {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup) //设置两个线程组.channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务器的通道实现.option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列等待连接个数.childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动连接状态.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline = socketChannel.pipeline();// 加入protobuf的解码器 指定解码默认实例pipeline.addLast(new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));pipeline.addLast(new NettyServerHandler());}});System.out.println("server is ready......");ChannelFuture channelFuture = serverBootstrap.bind(6668).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}}

新建NettyServerhandler

package com.dance.netty.netty.protobuf;import com.dance.netty.netty.protobuf.pojo.StudentPOJO;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.nio.charset.StandardCharsets;
public class NettyServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 读取从客户端发送的额StudentPOJO.studentStudentPOJO.Student student = (StudentPOJO.Student) msg;System.out.println("客户端发送的数据:" + student.getId() + " " + student.getName());}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(Unpooled.copiedBuffer("Hello 客户端", StandardCharsets.UTF_8));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();cause.printStackTrace();}
}

新建NettyClient

package com.dance.netty.netty.protobuf;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.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;public class NettyClient {public static void main(String[] args) throws InterruptedException {EventLoopGroup eventExecutors = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(eventExecutors).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline = socketChannel.pipeline();// 加入处理Protobuf的编码器pipeline.addLast(new ProtobufEncoder());pipeline.addLast(new NettyClientHandler());}});System.out.println("客户端 ok !");ChannelFuture sync = bootstrap.connect("127.0.0.1", 6668).sync();sync.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {eventExecutors.shutdownGracefully();}}}

新建NettyClientHandler

package com.dance.netty.netty.protobuf;import com.dance.netty.netty.protobuf.pojo.StudentPOJO;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;import java.nio.charset.StandardCharsets;public class NettyClientHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {// 发送一个Student对象到服务器StudentPOJO.Student dance = StudentPOJO.Student.newBuilder().setId(4).setName("dance").build();ctx.writeAndFlush(dance);}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf byteBuf = (ByteBuf) msg;System.out.println("服务器回复的消息: " + byteBuf.toString(StandardCharsets.UTF_8));System.out.println("服务器地址: " + ctx.channel().remoteAddress());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();cause.printStackTrace();}
}

测试

启动Server

启动Client

server is ready......
客户端发送的数据:4 dance
客户端 ok !
服务器回复的消息: Hello 客户端
服务器地址: /127.0.0.1:6668

使用SimpleChannelInBoundHandler定义泛型

package com.dance.netty.netty.protobuf;import com.dance.netty.netty.protobuf.pojo.StudentPOJO;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;import java.nio.charset.StandardCharsets;
//public class NettyServerHandler extends ChannelInboundHandlerAdapter {public class NettyServerHandler extends SimpleChannelInboundHandler<StudentPOJO.Student> {@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(Unpooled.copiedBuffer("Hello 客户端", StandardCharsets.UTF_8));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();cause.printStackTrace();}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, StudentPOJO.Student msg) throws Exception {System.out.println("客户端发送的数据:" + msg.getId() + " " + msg.getName());}
}

Protobuf快速入门实例2

需求

  1. 编写程序, 使用Protobuf完成如下功能
  2. 客户端可以随机发送studentPOJO/workerPOJO对象到服务器(通过Protobuf编码)
  1. 服务器接收StudentPOJO/WorkerPOJO对象, (需要判断是那种类型), 并显示信息(通过Protobuf解码)
  2. 具体 看老师演示(show time)

编写proto文件

syntax = "proto3"; // 版本option optimize_for = SPEED; // 加快解析option java_package = "com.dance.netty.netty.protobuf2.pojo"; // 指定包option java_outer_classname = "MyDataInfo"; // Java的外部类名message MyMessage{// 定义一个枚举类型enum DataType {StudentType = 0;WorkerType = 1;}// 用DataType来标识传的是哪个枚举类型DataType dataType = 1;// 表示每次枚举类型最多只能出现其中的一个, 节省空间oneof dataBody{Student student = 2;Worker worker = 3;}
}message Student {int32 id = 1;string name = 2;
}message Worker {int32 id = 1;string name = 2;
}

生成java类型并拷贝到项目

好大~

根据之前的案例1修改

修改NettyClientHandler

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {// 随机发送Student或者Workerint i = new Random().nextInt(3);MyDataInfo.MyMessage myMessage = null;if(0 == i){myMessage = MyDataInfo.MyMessage.newBuilder().setDataType(MyDataInfo.MyMessage.DataType.StudentType).setStudent(MyDataInfo.Student.newBuilder().setId(1).setName("flower").build()).build();}else{myMessage = MyDataInfo.MyMessage.newBuilder().setDataType(MyDataInfo.MyMessage.DataType.StudentType).setWorker(MyDataInfo.Worker.newBuilder().setId(2).setName("dance").build()).build();}ctx.writeAndFlush(myMessage);}

修改NettyServer

pipeline.addLast(new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));

修改NettyServerHandler

public class NettyServerHandler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyDataInfo.MyMessage msg) throws Exception {if(msg.getDataType() == MyDataInfo.MyMessage.DataType.StudentType){System.out.println("客户端发送的数据:" + msg.getStudent().getId() + " " + msg.getStudent().getName());}else if(msg.getDataType() == MyDataInfo.MyMessage.DataType.WorkerType){System.out.println("客户端发送的数据:" + msg.getWorker().getId() + " " + msg.getWorker().getName());}
}

测试

client

客户端 ok !
服务器回复的消息: Hello 客户端
服务器地址: /127.0.0.1:6668

Server

server is ready......
客户端发送的数据:2 dance
客户端发送的数据:2 dance
客户端发送的数据:1 flower

若有收获,就点个赞吧

17-跨语言调用 Google ProtoBuf相关推荐

  1. 使用thrift进行跨语言调用(php c# java)

    1:前言 实际上本文说的是跨进程的异构语言调用,举个简单的例子就是利用PHP写的代码去调C#或是java写的服务端.其实除了本文提供的办法还有其他办法,例如http+xml(json)等等都能做到. ...

  2. Java如何跨语言调用Python/R训练的模型

    在 如何使用sklearn进行在线实时预测(构建真实世界中可用的模型) 这篇文章中,我们使用 sklearn + flask 构建了一个实时预测的模型应用.无论是 sklearn 还是 flask,都 ...

  3. 跨语言调用Hangfire定时作业服务

    背景 Hangfire允许您以非常简单但可靠的方式执行后台定时任务的工作.内置对任务的可视化操作.非常方便. 但令人遗憾的是普遍都是业务代码和hagnfire服务本身聚合在一个程序中运行,极大的限制了 ...

  4. Dubbo 跨语言调用神兽:dubbo-go-pixiu

    简介:Pixiu 是基于 Dubbogo 的云原生.高性能.可扩展的微服务 API 网关.作为一款网关产品,Pixiu 帮助用户轻松创建.发布.维护.监控和保护任意规模的 API ,接受和处理成千上万 ...

  5. EasyPlayerPro(Windows)流媒体播放器开发之跨语言调用

    下面我们来讲解一下关于EasyPlayerPro接口的调用,主要分为C++和C#两种语言,C++也可以基于VC和QT进行开发,C++以VC MFC框架为例进行讲解,C#以Winform框架为例进行讲解 ...

  6. jsb调用java_cocos2dx-jsb 跨语言调用及第三方集成 - 过程记录

    1:C++中调用js方法: 问题:ios中当用户通过home键将游戏转入后台时,调用js中的暂停游戏方法: AppDelegate::applicationDidEnterBackground() 和 ...

  7. 跨语言rpc框架Thrift

    RPC 全称 Remote Procedure Call--远程过程调用.RPC技术简单说就是为了解决远程调用服务 的一种技术,使得调用者像调用本地服务一样方便透明 Thrift的定义   Thrif ...

  8. java 序列化 protobuf_java序列化机制之protobuf(快速高效跨语言)

    我们之前曾讲过java自带的一种序列化机制,但是这种机制效率太低,有很多缺点.因此也涌现出了很多优秀的系列化框架,比如说protobuf.protostuff.thrift.hession.kryo. ...

  9. server如何调用 thrift_一文带你了解 Thrift,一个可伸缩的跨语言 RPC 框架(pinpoint 源码分析系列)...

    Thrift 是什么研究分布式调用链工具pinpoint的时候,在源码里看到了Thrift相关的代码,所以来了兴趣,想研究研究这个框架.Thrift 目前是 Apache 的一个项目,但是它是由fac ...

最新文章

  1. 27、Python 面向对象(创建类、创建实例对象、访问属性、内置类属性、对象销毁、类的继承、方法重写、基础重载方法、运算符重载、类属性与方法、下划线双下划线)
  2. lua cocos 创建动画的几种方式
  3. HDU - 5769 Substring(后缀数组)
  4. openSUSE 11 上的配置可以Xmanager远程桌面
  5. 推荐一个很棒的开源工作流elsa-core
  6. libevent的使用(socket)
  7. 七年程序员生涯,我学到最重要的 6 个教训,别再中招!
  8. 3_python基础—运算符 2
  9. intelRealsense D435 python3的环境搭建
  10. 用几何(解析几何)方法求解概率问题
  11. java 撤销恢复按钮_再涨个姿势,我们常用的撤销和恢复功能,你知道它们使用了什么设计模式实现吗?...
  12. https原理:证书传递、验证和数据加密、解密过程解析
  13. php web browser,如何在PHP Scriptable Web Browser中調用javascript函數
  14. xdc如何设置输入延时
  15. PPT精典基础教程 .
  16. 旧手机改文件储存服务器,旧手机改成云服务器
  17. SQL经典面试题--留存率问题
  18. 网络计算机输入网络凭据,Win10访问局域网电脑提示需要输入网络凭证怎么办?
  19. 液晶显示屏的C语言编码,AMPIRE12864液晶C语言代码
  20. 如何编写makefile

热门文章

  1. Rust 中级教程 第5课——trait(3)
  2. 【Pytorch】利用Pytorch+GRU实现情感分类(附源码)
  3. 地产“罗生门”:是世茂“不讲武德”,还是福晟“谎话连篇”?
  4. mysql 远程访问不行解决方法 Host is not allowed to connect to this MySQL server
  5. 《黑客攻防技术宝典:Web实战篇》习题答案(一)
  6. 黑客攻防(一)网站信息收集
  7. QCC514x-QCC304x(headset)系列(实战篇)之3.1-按键模块详解
  8. 软件需求说明书(GB856T——88)基于协同的在线表格forture-sheet
  9. 四种最令人讨厌的编程语言
  10. python opc服务器和客户端互相发送信息并给出实例