网络一直是项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架。从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用的工具类,到后来Google开源的比较完善丰富的Volley,再到如今比较流行的Okhttp、Retrofit。他们之间存在异同,这个系列主要想通过对网络基础知识、Android网络框架的解析来理清他们的关系以及原理。
一.计算机网络体系结构
每个程序员的基本知识,OSI的七层模型:
其中 表示层和 会话层没有协议,所以我们重点解释一下其他5层作用
1.应用层:如http协议,它实际上是定义了如何包装和解析数据,应用层是http协议的话,则会按照协议规定包装数据,如按照请求行、请求头、请求体包装,包装好数据后将数据传至运输层。
2.传输层:运输层有TCP和UDP两种协议,分别对应可靠的运输和不可靠的运输,如TCP因为要提供可靠的传输,所以内部要解决如何建立连接、如何保证传输是可靠的不丢数据、如何调节流量控制和拥塞控制。关于这一层,我们平常一般都是和Socket打交道,Socket是一组封装的编程调用接口,通过它,我们就能操作TCP、UDP进行连接的建立等。我们平常使用Socket进行连接建立的时候,一般都要指定端口号,所以这一层指定了把数据送到对应的端口号。
3.网络层:这一层IP协议,以及一些路由选择协议等等,所以这一层的指定了数据要传输到哪个IP地址。中间涉及到一些最优线路,路由选择算法等等。
4.数据链路层:印象比较深的就是ARP协议,负责把IP地址解析为MAC地址,即硬件地址,这样就找到了对应的唯一的机器。
5.物理层:这一层就是最底层了,提供二进制流传输服务,也就是也就是真正开始通过传输介质(有线、无线)开始进行数据的传输了。
所以通过上面五层的各司其职,实现物理传输介质--MAC地址--IP地址--端口号--获取到数据根据应用层协议解析数据最终实现了网络通信和数据传输。
TCP和UDP使用IP协议从一个网络传送数据包到另一个网络。把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等。
二.HTTP相关
1.HTTP是无连接无状态的。
无连接:并不是说不需要连接,Http协议只是一个应用层协议,最终还是要靠运输层的如TCP协议向上提供的服务进行连接。无连接的含义是http约定了每次连接只处理一个请求,一次请求完成后就断开连接,这样主要是为了缓解服务器的压力,减小连接对服务器资源的占用。我的理解是,建立连接实际上是运输层的事,面向应用层的http来说的话,它就是无连接的,因为上层对下层无感知。
无状态:每个请求之间都是独立的,对于之前的请求事务没有记忆的能力。所以就出现了像
Cookie这种,用来保存一些状态的东西。
2.请求报文与响应报文
- 关于Get和Post的区别:
1.Get会把请求参数都拼接在url后面,最终显示在地址栏,而Post则会把请求参数数据放进请求体中,不会再地址栏显示出来
2.传递参数的长度限制,Get请求URL 的最大长度是 2048 个字符,Post无限制。
2.HTTP的缓存机制
Http的缓存主要利用header里的两个字段来控制:
① Cache-control主要包含以及几个字段:
- private:则只有客户端可以缓存
- public:客户端和代理服务器都可以缓存
- max-age:缓存的过期时间
- no-cache:需要使用对比缓存来验证缓存数据
- no-store:所有内存都不会进行缓存
②ETag:即用来进行对比缓存,Etag是服务端资源的一个标识码
当客户端发送第一次请求时服务端会下发当前请求资源的标识码Etag,下次再请求时,客户端则会通过header里的If-None-Match将这个标识码Etag带上,服务端将客户端传来的Etag与最新的资源Etag做对比,如果一样,则表示资源没有更新,返回304。
通过Cache-control和Etag的配合来实现Http的缓存机制。
4.,Http2.0相对于Http1.x的对比:
khttp支持配置使用Http 2.0协议,Http2.0相对于Http1.x来说提升是巨大的,主要有以下几点:
二进制格式:http1.x是文本协议,而http2.0是二进制以帧为基本单位,是一个二进制协议,一帧中除了包含数据外同时还包含该帧的标识:Stream Identifier,即标识了该帧属于哪个request,使得网络传输变得十分灵活。
多路复用:一个很大的改进,原先http1.x一个连接一个请求的情况有比较大的局限性,也引发了很多问题,如建立多个连接的消耗以及效率问题。
http1.x为了解决效率问题,可能会尽量多的发起并发的请求去加载资源,然而浏览器对于同一域名下的并发请求有限制,而优化的手段一般是将请求的资源放到不同的域名下来突破这种限制。
而http2.0支持的多路复用可以很好的解决这个问题,多个请求共用一个TCP连接,多个请求可以同时在这个TCP连接上并发,一个是解决了建立多个TCP连接的消耗问题,一个也解决了效率的问题。那么是什么原理支撑多个请求可以在一个TCP连接上并发呢?基本原理就是上面的二进制分帧,因为每一帧都有一个身份标识,所以多个请求的不同帧可以并发的无序发送出去,在服务端会根据每一帧的身份标识,将其整理到对应的request中。
header头部压缩:主要是通过压缩header来减少请求的大小,减少流量消耗,提高效率。因为之前存在一个问题是,每次请求都要带上header,而这个header中的数据通常是一层不变的。
支持服务端推送
4.HTTP的缺点
- 通信使用明文(不加密),内容可能被窃听(抓包工具可以获取请求和响应内容)
- 不验证通讯方的身分,任何人都坑你发送请求,不管对方是谁都返回相应
- 无法证明报文的完整性,可能会遭到篡改,即没有办法确认发出的请求/相应前后一致。
三.HTTPS
http是超文本传输协议,而https可以简单理解为安全的http协议。https通过在http协议下添加了一层ssl协议对数据进行加密从而保证了安全。https的作用主要有两点:
- 建立安全的信息传输通道,保证数据传输安全;
- 确认网站的真实性。
而非对称加密算法之所以能实现安全传输的核心精华就是:
公钥加密的信息只能用私钥解开,私钥加密的信息只能被公钥解开
对称加密(也叫私钥加密):加密和解密用的都是相同的秘钥,优点是速度快,缺点是安全性低。
常见的对称加密算法有DES、AES、RC4、IDEA。
非对称加密:非对称加密有一个秘钥对,分为公钥和私钥。一般来说,私钥自己持有,公钥可以公开给对方,优点是安全性比对称加密高,缺点是数据传输效率比对称加密低。采用公钥加密的信息只有对应的私钥可以解密。常见的非对称加密包括RSA、DSA/DSS等。
对于Https是对称加密和非对称加密结合使用,使用非对称加密完成秘钥的传递,然后使用对称秘钥进行数据加密和解密。二者结合既保证了安全性,又提高了数据传输效率。
1.HTTP与HTTPS的相同和异同点
①、HTTP与HTTPS的相同点:
大多数情况下,HTTP和HTTPS是相同的,因此都采用同一个基础协议,作为HTTP或者HTTPS客户端--浏览器/app等,设置一个连接到web服务器指定的宽口。当服务器接收到请求,它会返回一个状态码以及消息,这个回应可能是请求信息、或者指示某个错误发送的错误信息。系统使用统一资源定位符URI,因此资源可以被唯一指定。在表面上HTTPS和HTTP唯一不同的只是一个协议头HTTPS的说明,其他都一样。
②、HTTP与HTTPS的不同点:
- HTTPS需要用到CA申请证书。
- HTTP是超文本传输协议,信息是明文的;HTTPS则是具有安全性的SSL加密传输协议。
- HTTPS和HTTP使用的是完全不同的连接方式,用的端口也不一样,HTTP是80,HTTPS是443。
- HTTP的连接很简单,是无状态的,HTTPS是HTTP+SSL协议构建的,可进行加密传输、身份认证的网络协议,比HTTP协议安全。
2.HTTPS的加密过程:
①客户端首次发出请求包含以下内容:
- 支持的协议版本,比如TLS 1.0版本
- 一个客户端生成的随机数,稍后用于生成"对话密钥"
- 支持的加密方法,比如RSA公钥加密
- 支持的压缩方法
客户端发送的信息之中不包括服务器的域名,也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的提供的数字证书。这就是为什么通常一台服务器只能由一张数字证书的原因
对于虚拟主机的用户来说,这当然很不方便。2006年,TLS协议加入了Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。
②服务器收到请求首次回应:
- 协议的版本,比如TLS1.0版本,如果浏览器与服务器支持的版本不一致,服务器关闭加密通信
- 加密的算法
- 随机数
- 服务器证书(也就是非对称加密的公钥)
采用HTTPS协议的服务器必须要有一套数字证书,可以是自己制作或者CA证书。区别就是自己制作的证书需要客户端验证通过,才可以继续访问,而使用CA证书则直接去证书机构验证请求。这套证书其实就是一堆公钥和私钥。公钥给别人加密使用,私钥给自己解密使用。服务器在接收到客户端的请求后,服务器需要确定加密协议的版本,以及加密的算法,然后也生成一个随机数。
③客户端验证证书:
- 首先验证证书的安全性
- 验证通过之后,客户端会生成一个随机数pre-master secret,然后使用证书中的公钥进行加密,然后传递给服务器端(将客户端生成的对称加密秘钥用服务器传下来的公钥进行加密)
④服务器收到加密信息
服务器收到使用公钥加密的内容,在服务器端使用私钥解密之后获得随机数pre-master secret,然后根据radom1、radom2、pre-master secret通过一定的算法得出一个对称加密的秘钥,作为后面交互过程中使用对称秘钥。同时客户端也会使用radom1、radom2、pre-master secret,和同样的算法生成对称秘钥。
⑤服务器最后的回应
服务器生成"会话密钥"后,向客户端最后发送下面信息:
1、编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
2、服务器握手结束通知,表示服务器握手阶段已经结束。这一项同时也是前面所有内容的hash值,用来供客户端校验。
⑥客户端解密
客户端用之前生成的私钥解密服务器传过来的信息,于是获取了解密后的内容。
至此,整个握手阶段全部结束了。再后续的交互中就使用上一步生成的对称秘钥对传输的内容进行加密和解密,就完全是使用普通HTTP协议,只不过用"会话密钥"加密内容。
上面产生的随机数,是整个握手阶段的出现的第三个随机数,又称"pre-master key"。有了它之后,客户端和服务器同时有了三个随机数,接着双方就用事先协商的加密方法,各自生成本地会话所用的同一把"会话密钥"。
为什么一定要用三个随机数,来生成"会话密钥"?
答:不管是客户端还是服务器,都是下需要随机数,这样生成的密钥才不会每次都一样,由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出的密钥的随机性。
对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上第一步、第三步消息中的随机数,三个随机数通过一个密钥导出器最终导出一个对称密钥。pre master 的存在在于SSL协议不信任每一个主机都能产生完全的随机数,如果随机数不随机,那么pre master secret就可能被猜出来,那么仅适用于pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机数可能完全不随机,但是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。
3.HTTPS的优点和缺点
①优点:
- 内容加密,建立一个信息的安全通道,来保证数据传输过程的安全性。
- 身份认证,确认网站的真是性。
- 数据完整性,防止内容被第三方冒充或者篡改。
②缺点: - 于要对数据进行加密,认证,所以注定他会比HTTP慢,当然现在也有很多优化。
处于安全考虑,浏览器是不会再本地保存HTTPS缓存。实际上,只要在HTTP头中使用特定的命令,HTTPS是可以被缓存的。Firefox默认只在内存中缓存HTTS。但是,只要在请求头中有Cache-Control:Public,缓存就会被写到磁盘上,IE只要http头允许就可以缓存https内容,缓存策略与是否使用HTTPS协议无关。
四.TCP相关
TCP面向连接,提供可靠的数据传输。在这一层,我们通常都是通过Socket Api来操作TCP,建立连接等等。
1、三次握手建立连接
第一次:发送SNY=1表示此次握手是请求建立连接的,然后seq生成一个客户端的随机数X
第二次:发送SNY=1,ACK=1表示是回复请求建立连接的,然后ack=客户端的seq+1(这样客户端收到后就能确认是之前想要连接的那个服务端),然后把服务端也生成一个代表自己的随机数seq=Y发给客户端。
第三次:ACK=1。 seq=客户端随机数+1,ack=服务端随机数+1(这样服务端就知道是刚刚那个客户端了)
为什么建立连接需要三次握手?
第三次握手是为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误
具体情况就是:C端发出去的第一个网络连接请求由于某些原因在网络节点中滞留了,导致延迟,直到连接释放的某个时间点才到达S端,这是一个早已失效的报文,但是此时S端仍然认为这是C端的建立连接请求第一次握手,于是S端回应了C端,第二次握手。如果只有两次握手,那么到这里,连接就建立了,但是此时C端并没有任何数据要发送,而S端就会傻傻的等待着,造成很大的资源浪费。所以需要第三次握手,只有C端再次回应一下,就可以避免这种情况。
2、四次握手断开连接
为什么比建立连接时多了一次握手?
可以看到这里服务端的ACK(回复客户端)和FIN(终止)消息并不是同时发出的,而是先ACK,然后再FIN,这也很好理解,当客户端要求断开连接时,此时服务端可能还有未发送完的数据,所以先ACK,然后等数据发送完再FIN。这样就变成了四次握手了。
3、TCP和UDP的区别
TCP (传输控制协议)
- 建立连接,形成传输数据的通道
- 在连接中进行大数据传输(数据大小不收限制)
- 通过三次握手完成连接,是可靠协议,安全送达
- 必须建立连接,效率会稍低
UDP (用户数据报协议)
- 将数据及源和目的封装成数据包中,不需要建立连接
- 每个数据报的大小限制在64K之内
- 因为无需连接,因此是不可靠协议
- 不需要建立连接,速度快
五.Socket
Socket是一组操作TCP/UDP的API,像HttpURLConnection和Okhttp这种涉及到比较底层的网络请求发送的,最终当然也都是通过Socket来进行网络请求连接发送,而像Volley、Retrofit则是更上层的封装,最后是依靠HttpURLConnection或者Okhttp来进行最终的连接建立和请求发送。
Socket的简单使用的话应该都会,两个端各建立一个Socket,服务端的叫ServerSocket,然后建立连接即可。
六特别感谢:
https://juejin.im/post/5b49f9fbf265da0f563dc9d8
https://www.jianshu.com/p/116ebf3034d9