美文网首页
Android 网络优化及protobuf

Android 网络优化及protobuf

作者: maybe0813 | 来源:发表于2021-05-14 20:23 被阅读0次

    Android 网络优化及protobuf

    https是常用的互联网应用层协议,客户端的一次请求大致经历了:客户端获取URL - > DNS解析 - > 建立HTTP连接 - >发送HTTP请求 几个阶段。

    可以发现有三个可以优化的地方:

    • 直接使用 IP 地址,去除 DNS 解析步骤;

    • 连接复用;

    • 压缩数据,减小传输的数据大小。

    DNS优化

    DNS(Domain Name System),它的作用是根据域名查出IP地址,它是HTTP协议的前提,只有将域名正确的解析成IP地址后,后面的HTTP流程才能进行。DNS 完整的解析流程很长,会先从本地系统缓存取,若没有就到最近的 DNS 服务器取,若没有再到主域名服务器取,每一层都有缓存,但为了域名解析的实时性,每一层缓存都有过期时间。

    传统的DNS解析机制有几个缺点:

    • 缓存时间设置得长,域名更新不及时,设置得短,大量 DNS 解析请求影响请求速度;
    • 域名劫持,容易被中间人攻击,或被运营商劫持,把域名解析到第三方 IP 地址;
    • DNS 解析过程不受控制,无法保证解析到最快的IP;

    针对传统DNS的缺点,HTTPDNS主要有以下优点:

    • 域名防劫持
    • 智能调度(获取最快最优IP)

    相关文章推荐 https://mp.weixin.qq.com/s/iaPtSF-twWz-AN66UJUBDg

    百度、阿里、腾讯都推出了自己的HTTPDNS方案。

    百度云 https://cloud.baidu.com/doc/HTTPDNS/s/ujwvxm073

    阿里云 https://help.aliyun.com/document_detail/30103.html?spm=a2c4g.11186623.6.543.665c3eabM102wL

    腾讯云 https://cloud.tencent.com/product/cns?fromSource=gwzcw.2602306.2602306.2602306&utm_medium=cpc&utm_id=gwzcw.2602306.2602306.2602306#advantage

    连接复用

    HTTP/2主要是为了解决现HTTP 1.1性能不好的问题才出现的。当初Google为了提高HTTP性能,做出了SPDY,它就是HTTP/2的前身,后来也发展成为HTTP/2的标准。

    HTTP/2兼容HTTP 1.1,例如HTTP Method,Status code,URI以及大部分Header Fields。

    HTTP/2通过以下方法减少latency,用来改进页面加载的速度,

    1. HTTP Header的压缩,采用的是HPack算法。
    2. HTTP/2的Server Push,非常重要的一个特性。
    3. 请求的pipeline。
    4. 修复在HTTP 1.x的队头阻塞问题。
    5. 在单个TCP连接里多工复用请求。

    HTTP/2支持HTTP 1.1里的大部分use case,例如桌面浏览器、移动浏览器、Web API、Web Server、代理服务器、反向代理服务器、防火墙和CDN等。

    参考博客 https://www.cnblogs.com/confach/p/10141273.html

    简单来说就是客户端和服务端都使用HTTP/2

    数据压缩

    数据对请求速度的影响分两方面,一是压缩率,二是解压序列化反序列化的速度。目前最流行的两种数据格式是 json 和 protobuf,json 是字符串,protobuf 是二进制,即使用各种压缩算法压缩后,protobuf 仍会比 json 小,数据量上 protobuf 有优势,序列化速度 protobuf 也有一些优势 。

    相比其他格式,protobuf优势有如下几点

    1. 序列化后体积相比Json和XML很小,适合网络传输

    2. 支持跨平台多语言

    3. 消息格式升级和兼容性还不错

    4. 序列化反序列化速度很快,快于Json的处理速速
      PS:在一个需要大量的数据传输的场景中,如果数据量很大,那么选择protobuf可以明显的减少数据量,减少网络IO,从而减少网络传输所消耗的时间。

    protobuf使用

    protobuf GitHub仓库地址 https://github.com/protocolbuffers/protobuf/tree/master/java

    1. 添加gradle插件

      classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.13'
      
    2. 应用插件

      apply plugin: 'com.google.protobuf'
      
      protobuf {
          protoc {
              artifact = 'com.google.protobuf:protoc:3.11.0'
          }
          generateProtoTasks {
              all().each { task ->
                  task.builtins {
                      java {
                          option "lite"
                      }
                  }
              }
          }
      }
      
    3. 添加依赖

      implementation 'com.google.protobuf:protobuf-javalite:3.11.0'
      
    4. 在java文件夹同级目录下创建proto文件夹,并创建.proto文件


      proto_create.png
    5. 填写.proto 文件内容,参考语法 https://blog.csdn.net/qq_22660775/article/details/89163881

      syntax = "proto3";//proto3
      
      option java_package = "com.example.proto";//生成的java类的包名
      
    6. 编译构建,就会在生成对应的java文件


      proto_build.png
    7. 调用对应的java API

              //构建对象
              Demo2.Test test = Demo2.Test.newBuilder()
                      .setCode("co")
                      .setNumber(24)
                      .setD(2.22)
                      .setF(1.5f)
                      .addList("sd")
                      .putMap(15,"map12")
                      .build();
              //序列化后的长度
              int size = test.getSerializedSize();
              //序列化
              byte[] bytes2 = test.toByteArray();
              //反序列化
              try {
                  Demo2.Test demoTest2 = Demo2.Test.parseFrom(bytes2);
                  //javalite版无法使用JsonFormat
      //            JsonFormat.printer().print((MessageOrBuilder)demoTest2);
                  //使用fastjson
                  Log.d("protoString", JSON.toJSONString(demoTest2));
              } catch (InvalidProtocolBufferException e) {
                  e.printStackTrace();
              }
      

      比较遗憾的是javalite版无法使用JsonFormat,曾经尝试把protobuf-java-util中的类拷贝下来,但由于util包依赖太多,最终放弃了

      使用fastjson打印结果中数据,虽然内容变多了,但核心内容都在,可以勉强使用。

      {
          "code": "co",
          "codeBytes": {
              "empty": false,
              "validUtf8": true
          },
          "d": 2.22,
          "defaultInstanceForType": {
              "code": "",
              "codeBytes": {
                  "empty": true,
                  "validUtf8": true
              },
              "d": 0,
              "defaultInstanceForType": {
                  "$ref": "@"
              },
              "f": 0,
              "initialized": true,
              "listCount": 0,
              "listList": [],
              "map": {},
              "mapCount": 0,
              "mapMap": {},
              "number": 0,
              "parserForType": {},
              "serializedSize": 0
          },
          "f": 1.5,
          "initialized": true,
          "listCount": 1,
          "listList": [
              "sd"
          ],
          "map": {
              "15": "map12"
          },
          "mapCount": 1,
          "mapMap": {
              "15": "map12"
          },
          "number": 24,
          "parserForType": {
              "$ref": "$.defaultInstanceForType.parserForType"
          },
          "serializedSize": 35
      }
      
    1. 推荐Android studio 安装两个插件


      proto_plugin.png
      • protocol-buffer-editor 插件(语法高亮)

      • pojo to proto 插件(拷贝java bean文件,生成proto文件的内容)

    pojo_copy.png pojo_paste.png

    其他

    1. 根据网络情况下发图片,在2G/3G/4G/5G/WIFI下分别获取不同分辨率的图片
    2. 开启数据压缩(okhttp默认支持接收gzip压缩)
    3. 根据网络情况下发图片,在2G/3G/4G/5G/WIFI下分别获取不同分辨率的图片
    4. WIFI下,按需提前上传下载大数据包
    5. 使用长连接保活时考虑智能心跳包时间间隔

    相关文章

      网友评论

          本文标题:Android 网络优化及protobuf

          本文链接:https://www.haomeiwen.com/subject/quqfjltx.html