E2c1b9fbcce578a4adf59c6e668ee39d
Android 架构之网络框架(上)

随着最近几年移动端的不断发展,加上移动互联网下沉,大型App越来越多,如抖音、头条等,日活不断增长。而飞速发展的业务也对移动端架构不断提出新要求,越来越多的公司需要应付大体量的用户。

《亿级Android架构》专栏尝试基于本人的工作经验,结合自己对于国内大厂如阿里、腾讯的开源架构的思考,针对Android架构这个话题写一些个人理解和总结。希望读者指正交流。

网络模块是大多数App的核心模块,涉及的技术点也很多,本文以网络为核心技术点,从以下几个方面逐步阐述,分成上下两篇写作。

本篇我们从OkHttp入手,谈一谈常规的网络框架设计和常用的网络优化方案。

  1. 网络框架OkHttp
    • 简洁易用的接口
    • 拦截器机制,网络重试与跳转
    • 连接池复用
  2. 网络加速
    • HttpDNS与IP直连
    • 连接加速:短连接复用、Http2多路复用、长连接
  3. 数据压缩与序列化
    • Json vs ProtoBuf
    • 压缩算法
    • 序列化
  4. 长连接技术与Mars架构
    • 智能心跳机制
    • 自动重连
    • Android跨进程实现
    • 智能唤醒
  5. 如何应对复杂网络
    • 弱网
    • 网络超时、振荡
    • 404与DNS劫持
  6. 如何保证网络数据安全
    • TLS协议,握手与证书
    • 数据签名及校验

1. 网络框架OkHttp

在 Android、Java 开发领域中,相信大家都听过或者在使用 Square 家大名鼎鼎的网络请求库——OkHttp——https://github.com/square/okhttp ,当前多数著名的开源项目如 Fresco、Glide、 Picasso、 Retrofit都在使用 OkHttp,而且该库也被加入到了Android系统内部,为广大的开发者提供网络服务。

OkHttp是目前最流行的Android网络框架,相信大多数同学都在使用它。因此,下面对OkHttp的优势和架构进行简明扼要的说明。

1. 简洁易用的接口

OkHttp对外提供了简洁易用的同步、异步网络请求接口:

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url(url)
        .build();
client.newCall(request).enqueue(new Callback() {
    public void onFailure(Request request, IOException e)  {}
    public void onResponse(Response response) throws IOException {}
});

业界大多数都是结合RetrofitRxJava一起使用,代码简洁优雅。

2. 拦截器机制

OkHttp对外提供了两种拦截器:AppInterceptorNetworkInterceptor,前者可以用作业务拦截器,一般对全局的网络请求添加一些通用的业务Header、Query参数等;而后者可以用作网络拦截器,可以对全局的网络数据做底层的监控、打印log等。

内部的实现是采用了责任链模式,拦截器逐个触发,类似View的Touch事件消费机制。AppInterceptor在所有拦截器最上层,而NetworkInterceptor则在最下层。

另外,在这两种拦截器中间,还有很多非常有用的默认拦截器,这里随机挑一个拦截器简单说下原理:

2.1 重试与跳转 RetryAndFollowupInterceptor

对于Retry的意思是,本次网络请求失败了,但是,有的错误类型其实是可以自动重试的,没必要直接抛出失败给业务层。

具体有下面一些情况:

  • 如果由于证书问题导致ssl握手失败,或者没有对等证书(访问网站的证书不在你的信任证书列表),则无需重试;
  • 如果请求已经成功发出,然后发生网络异常,且返回body未被标记为不可重复,则自动重试;
  • 如果是socket连接超时,则会重试连接下一个DNS IP;
  • 如果所有可选路由均失败,则停止重试。

对于Followup的意思是,当前网络请求成功了,也有结果返回了,但是结果并不是200 OK,而是类似重定向3xx,或者未授权401等。而这些响应码实际上是允许我们继续发起请求的,比如重定向,OkHttp会自动去访问这个新的地址;比如未授权,OkHttp会自动加上授权信息,然后继续访问。

3. 连接池

大家知道,一个Http请求除了真正的数据传输,还需要花费一段时间在TCP连接的建立上。如果每次网络请求都要去发起一个TCP连接,那显然会非常影响网络请求速度,尤其是当多数网络请求都是连接同一个远程地址时,反复建立连接显得非常浪费。

Http 1.1已经提供了Keep-Alive机制,也就是在数据传输完毕后,仍然会保留这条连接一段时间,下次无需再次握手即可进行数据传输。

而在OkHttp内部,也维护了一个Socket连接池,里面存放了5个并发Keep-Alive的Socket连接,每一个连接存活5分钟。当你需要建立连接时,先来池子里查一下,如果有可用的连接,则直接复用即可。

当然了,连接池也有它的弊端,如果空闲连接较多,那就成了僵尸连接,白白占用了资源,还影响到其他客户端的连接;而且有的服务器只能保持有限的并发连接数,这也会影响到其他用户的使用。不过,在OkHttp里,做了一套不错的连接清理机制,可以尽可能早地关闭空闲连接,提高连接活跃度。下次有空可以再细谈。

4. 其他

如果对OkHttp原理感兴趣,也可以读一下之前写的《带你学开源项目 OkHttp:自己动手实现OkHttp》

2. 网络加速

丰富的OkHttp基础网络框架已经能赋予大多数常规App需要的网络连接能力了,但是对于大型App而言,他们的用户可能覆盖全国各种网络环境下,因此需要尽可能去加速网络,保证各个环境下的用户都能最快获取数据。

top Created with Sketch.