目录
2.HttpURLConnection与HttpClient
一、网络框架对比和源码分析
自己去设计网络请求框架,怎么做?
1.Volley:
其中蓝色的是主线程,绿色的是缓存线程,黄色的是网络线程
1.当一个Request请求添加到RequestQueue请求队列中,Volley就开始工作了。RequestQueue请求队列中持有一个CacheDispatcher缓存管家和一组NetworkDispatcher网络管家。
2.RequestQueue会先叫来CacheDispatcher缓存管家,让他去看看,当前请求的数据在没在cache中。
2.1.当前的数据在cache中,那就把数据从cache中取出来,然后经过一番加工,将加工好的数据交付给主线程。
2.2.当前数据没在cache中,进行第3步。
3.进行到了这一步,那肯定是数据没有在缓存中,那只能去网络中获取了,这时候RequestQueue会叫来NetworkDispatcher,NetworkDispatcher可是有一帮呢,其实这是一个线程池,默认情况下会启动4个线程去网络下载数据。所以RequestQueue把当前闲着的NetworkDispatcher叫来,给他们分配任务。
4.拿到任务的NetworkDispatcher就会去网络上下载数据了,与此同时,他会判断下载到的数据能否写入到cache缓存中,如果可以的话就写入cache,以便于下一次直接从cache中获取到数据。最后,将数据加工,交付给主线程。
volley中为了提高请求处理的速度,采用了ByteArrayPool进行内存中的数据存储的,如果下载大量的数据,这个存储空间就会溢出,所以不适合大量的数据。
volley 的线程池是基于数组实现的,即newFixedThreadPool(4)核心线程数不超过4个,也不会自动扩展,一旦大数据上传或者下载长时间占用了线程资源,后续所有的请求都会被阻塞。最后,Volley是不适合上次和下载大文件
重复请求问题
setRetryPolicy 设置超时时间,重连次数。
2.okhttp
原理参考:OkHttp原理
okhttp如何处理网络缓存的: 使用CacheControl处理,Request.Builder().cacheControl(cache)。
HttpUrlConnection 和 okhttp关系: HttpUrlConnection 在Android4.4之后,是通过okhttp实现的,用HttpHandler作为桥梁过渡。
建造者模式。分发器、拦截器;
2.1 分发器
分发器用线程池和队列来调度任务请求。分同步请求和异步请求。
2.2 拦截器
五大默认拦截器:是否retry, 桥接应用与服务器,处理缓存,建立与服务器的连接,与服务器通信。
2.2.1 自定应应用拦截器和网络拦截器区别
- 首先,应用拦截器在
RetryAndFollowUpInterceptor
和CacheInterceptor
之前,所以一旦发生错误重试或者网络重定向,网络拦截器可能执行多次,因为相当于进行了二次请求,但是应用拦截器永远只会触发一次。另外如果在CacheInterceptor
中命中了缓存就不需要走网络请求了,因此会存在短路网络拦截器的情况。- 其次,除了
CallServerInterceptor
之外,每个拦截器都应该至少调用一次realChain.proceed
方法。实际上在应用拦截器这层可以多次调用proceed
方法(本地异常重试)或者不调用proceed
方法(中断),但是网络拦截器这层连接已经准备好,可且仅可调用一次proceed
方法。- 最后,从使用场景看,应用拦截器因为只会调用一次,通常用于统计客户端的网络请求发起情况;而网络拦截器一次调用代表了一定会发起一次网络通信,因此通常可用于统计网络链路上传输的数据。
作者:程序员江同学
链接:https://juejin.cn/post/7020027832977850381
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.3 OKHttp
如何复用TCP
连接
TCP握手耗时,新建连接消耗资源。复用TCP能减少请求时间。
# ExchangeFinder
//为承载新的数据流 寻找 连接。寻找顺序是 已分配的连接、连接池、新建连接
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
synchronized (connectionPool) {
// 1.尝试使用 已给数据流分配的连接.(例如重定向请求时,可以复用上次请求的连接)
releasedConnection = transmitter.connection;
result = transmitter.connection;
if (result == null) {
// 2. 没有已分配的可用连接,就尝试从连接池获取。(连接池稍后详细讲解)
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
result = transmitter.connection;
}
}
}
synchronized (connectionPool) {
if (newRouteSelection) {
//3. 现在有了IP地址,再次尝试从连接池获取。可能会因为连接合并而匹配。(这里传入了routes,上面的传的null)
routes = routeSelection.getAll();
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, false)) {
foundPooledConnection = true;
result = transmitter.connection;
}
}
// 4.第二次没成功,就把新建的连接,进行TCP + TLS 握手,与服务端建立连接. 是阻塞操作
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
synchronized (connectionPool) {
// 5. 最后一次尝试从连接池获取,注意最后一个参数为true,即要求 多路复用(http2.0)
//意思是,如果本次是http2.0,那么为了保证 多路复用性,(因为上面的握手操作不是线程安全)会再次确认连接池中此时是否已有同样连接
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
// 如果获取到,就关闭我们创建里的连接,返回获取的连接
result = transmitter.connection;
} else {
//最后一次尝试也没有的话,就把刚刚新建的连接存入连接池
connectionPool.put(result);
}
}
return result;
}
2.4 OKHttp
空闲连接如何清除
- 在将连接加入连接池时就会启动定时任务
- 有空闲连接的话,如果最长的空闲时间大于5分钟 或 空闲数 大于5,就移除关闭这个最长空闲连接;如果 空闲数 不大于5 且 最长的空闲时间不大于5分钟,就返回到5分钟的剩余时间,然后等待这个时间再来清理。
- 没有空闲连接就等5分钟后再尝试清理。
- 没有连接不清理。
2.5 OkHttp 优点
- 使用简单;
- 扩展性强:自定义应用拦截器,网络拦截器等;
- 功能强大,支持多种协议;
- 通过连接池复用底层TCP,减少请求延时;
- 支持GZIP,减少数据流量;
- ……
2.6 使用方法参考
- OkHttpClient 申明工具类,
- Request 封装请求的地址参数等,
- 并传入newCall做参数,
- enqueue插入队列,
- 在onResponse 回调中处理。
可和RxJava, Retrofit 搭配使用。
3. RXJava
建造者模式、观察者模式、链式处理,
4.Retrofit
- 底层基于OkHttp,
- 用注解方式申明url路径等,语言简洁, 链式处理,
- 动态代理 封装了一些通用逻辑
5.其它
WebSocket与socket的区别:WebSocket 和Http都是可靠传输的应用层协议,但WebSocket能双向通信。Socket不是协议,是为了通信抽象出来的一层接口。 WebSocket用于即时通讯,替代轮询。
二、网络细节
1.Get与post区别
参考:Get和post区别
(1)post更安全(不会作为url的一部分,不会被缓存、保存在服务器日志、以及浏览器浏览记录中)
(2)post发送的数据更大(get有url长度限制,非协议的限制,而是浏览器和服务器限制了长度 Get传参长度的误解)
(3)post能发送更多的数据类型(get只能发送ASCII字符)
(4)post比get慢
(5)post用于修改和写入数据,get一般用于搜索排序和筛选之类的操作(淘宝,支付宝的搜索查询都是get提交),目的是资源的获取,读取数据.
get效率高
2.HttpURLConnection与HttpClient
Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。
Android6.0 后已经不支持HttpClient。
三、网络请求流程
描述一次网络请求的流程:
- 通过URL查找IP;
- 对IP结果建立TCP链接;
- 向服务器发送数据;
- 服务器解析并返回数据;
- 浏览器解析HTML;
client如何确定自己发送的消息被server收到?: 需要应用层实现,server收到信息后给予反馈。
Https请求慢的解决办法?(提示:DNS,携带数据,直接访问IP)
四、网络协议
1.HTTP相关
HTTP协议:是用于从万维网服务器传输超文本到本地浏览器的传送协议。
1、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。
2、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
3.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
4.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
5、支持B/S及C/S模式。
2.HTTP与HTTPS
HTTP与HTTPS的区别以及如何实现安全性:https安全,效率低,要安装证书,申请证书会产生费用,可以防止运营商劫持;
https内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。
为什么内容传输用的是对称加密:
首先:非对称加密的加解密效率是非常低的,而 http 的应用场景中通常端与端之间存在大量的交互,非对称加密的效率是无法接受的。
另外:在 HTTPS 的场景中只有服务端保存了私钥,一对公私钥只能实现单向的加解密,所以 HTTPS 中内容传输加密采取的是对称加密,而不是非对称加密。
3.http statusCode(状态码)
1xx:指示信息,表示请求已经接收,继续处理。
201-206都表示服务器成功处理了请求的状态代码,说明网页可以正常访问。
300-3007表示的意思是:要完成请求,您需要进一步进行操作。通常,这些状态代码是永远重定向的。
4XXHTTP状态码表示请求可能出错,会妨碍服务器的处理。 (客户端错误)
500至505表示的意思是:服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。
4.TCP与UDP
TCP与UDP的区别:
1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。