Android工程师应该懂得的网络知识

下面就以比较经常看到的的5层结构为例:
在这里插入图片描述
1)应用层:如http协议,它实际上是定义了如何包装和解析数据,应用层是http协议的话,则会按照协议规定包装数据,如按照请求行、请求头、请求体包装,包装好数据后将数据传至运输层。

2)运输层:TCP和UDP两种协议,使用Socket进行连接建立的时候,一般都要指定端口号,所以这一层指定了把数据送到对应的端口号。

3)网络层:这一层IP协议,以及一些路由选择协议等等,所以这一层的指定了数据要传输到哪个IP地址。中间涉及到一些最优线路,路由选择算法等等。

4)数据链路层:印象比较深的就是ARP协议,负责把IP地址解析为MAC地址,即硬件地址,这样就找到了对应的唯一的机器。

5)物理层:这一层就是最底层了,提供二进制流传输服务,也就是也就是真正开始通过传输介质(有线、无线)开始进行数据的传输了。

实现物理传输介质–MAC地址–IP地址–端口号–获取到数据根据应用层协议解析数据最终实现了网络通信和数据传输。

1.1 正确理解HTTP的“无连接”“与无状态”
无连接的含义是http约定了每次连接只处理一个请求,一次请求完成后就断开连接,这样主要是为了缓解服务器的压力,减小连接对服务器资源的占用。我的理解是,建立连接实际上是运输层的事,面向应用层的http来说的话,它就是无连接的,因为上层对下层无感知。

Http协议只是一个应用层协议,最终还是要靠运输层的如TCP协议向上提供的服务进行连接。

无状态的指每个请求之间都是独立的,对于之前的请求事务没有记忆的能力。所以就出现了像Cookie这种,用来保存一些状态的东西。

1.2 请求报文与响应报文
请求报文:
在这里插入图片描述

响应报文:
在这里插入图片描述
关于Get和Post,我们都熟知的关于Get和Post的区别大致有以下几点:

1)Get会把请求参数都拼接在url后面,最终显示在地址栏,而Post则会把请求参数数据放进请求体中,不会再地址栏显示出来;

2)传递参数的长度限制。

问题:

对于第1)点,如果是在浏览器里把隐私数据暴露在地址栏上确实不妥,但是如果是在App开发中呢,没有地址栏的概念,那么这一点是不是还会成为选择post还是get的制约条件;

对于第2)点,长度的限制应该是浏览器的限制,跟get本身无关,如果是在App开发中,这一点是否也可以忽略。

1.3 HTTP的缓存机制
Okhttp中对于网络请求缓存这一块就是利用了Http的的缓存机制
Http的缓存主要利用header里的两个字段来控制:即Cache-control和ETag

1)Cache-control主要包含以及几个字段:

private:则只有客户端可以缓存;

public:客户端和代理服务器都可以缓存;

max-age:缓存的过期时间;

no-cache:需要使用对比缓存来验证缓存数据;

no-store:所有内存都不会进行缓存。

实际上就是在这里面设置了一个缓存策略,由服务端第一次通过header下发给客户端,可以看到:

max-age:即缓存过期的时间,则之后再次请求,如果没有超过缓存失效的时间则可以直接使用缓存;

no-cache:需要使用对比缓存来验证缓存数据,如果这个字段是打开的,则就算max-age缓存没有失效,则还是需要发起一次请求向服务端确认一下资源是否有更新,通过Etag对比。如果服务端确认资源没有更新,则返回304,取本地缓存即可,如果有更新,则返回最新的资源;

ETag:即用来进行对比缓存,Etag是服务端资源的一个标识码
当客户端发送第一次请求时服务端会下发当前请求资源的标识码Etag,下次再请求时,客户端则会通过header里的If-None-Match将这个标识码Etag带上,服务端将客户端传来的Etag与最新的资源Etag做对比,如果一样,则表示资源没有更新,返回304。

1.4 HTTP的Cookie
Http协议是无状态的,而Cookie就是用来在本地缓存记住一些状态的,一个Cookie一般都包含domin(所属域)、path、Expires(过期时间)等几个属性。服务端可以通过在响应头里的set-cookies来将状态写入客户端的Cookie里。下次客户端发起请求时可以将Cookie带上。

1.5 Https
Https=Http+Ssl,之所以能保证安全主要的原理就是利用了非对称加密算法
对称加密算法不安全,因为双方是用统一的密匙进行加密解密的,只要双方任意一方泄漏了密匙,那么其他人就可以利用密匙解密数据。

非对称加密算法之所以能实现安全传输的核心精华就是:公钥加密的信息只能用私钥解开,私钥加密的信息只能被公钥解开。

服务端申请CA机构颁发的证书,则获取到了证书的公钥和私钥,私钥只有服务器端自己知道,而公钥可以告知其他人,如可以把公钥传给客户端

Https的工作过程远比这要复杂:
1.客户端还需要验证服务端传来的CA证书的合法性、有效性,因为存在传输过程CA证书被人调包的风险,涉及到客户端如何验证服务器证书的合法性的问题,保证通信双方的身份合法;

2.非对称算法虽然保证了数据的安全,但是效率相对于对称算法来说比较差,如何来优化,实现既保证了数据的安全,又提高了效率。

首先CA证书一般包括以下内容:

证书的颁发机构以及版本;
证书的使用者;
证书的公钥;
证书有效时间;
证书的数字签名Hash值以及签名Hash算法(这个数字签名Hash值是用证书的私钥加密过的值);
等等。

客户端验证证书的合法性:先利用获取到的公钥来解密证书中的数字签名Hash值1(因为它是利用私钥加密的嘛),然后在利用证书里的签名Hash算法生成一个Hash值2,如果两个值相等,则表示证书合法,服务器端可以被信任。

1.6 Http 2.0
Http2.0相对于Http1.x来说提升是巨大的,主要有以下几点:

1)二进制格式:http1.x是文本协议,而http2.0是二进制以帧为基本单位,是一个二进制协议,一帧中除了包含数据外同时还包含该帧的标识:Stream Identifier,即标识了该帧属于哪个request,使得网络传输变得十分灵活;

2)多路复用:

http1.x为了解决效率问题,可能会尽量多的发起并发的请求去加载资源,然而浏览器对于同一域名下的并发请求有限制,而优化的手段一般是将请求的资源放到不同的域名下来突破这种限制。

而http2.0支持的多路复用可以很好的解决这个问题,多个请求共用一个TCP连接,多个请求可以同时在这个TCP连接上并发,一个是解决了建立多个TCP连接的消耗问题,一个也解决了效率的问题。

那么是什么原理支撑多个请求可以在一个TCP连接上并发呢?基本原理就是上面的二进制分帧,因为每一帧都有一个身份标识,所以多个请求的不同帧可以并发的无序发送出去,在服务端会根据每一帧的身份标识,将其整理到对应的request中。

3)**header头部压缩:**主要是通过压缩header来减少请求的大小,减少流量消耗,提高效率。因为之前存在一个问题是,每次请求都要带上header,而这个header中的数据通常是一层不变的。

4)支持服务端推送。
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。

HTTP/1.0 版的主要缺点是,每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。

1.0版规定,头信息必须是 ASCII 码,后面的数据可以是任何格式。因此,服务器回应的时候,必须告诉客户端,数据是什么格式,这就是Content-Type字段的作用。

TCP相关

TCP面向连接,提供可靠的数据传输。在这一层,我们通常都是通过Socket Api来操作TCP,建立连接等等。

三次握手建立连接
在这里插入图片描述
第一次:发送SNY=1表示此次握手是请求建立连接的,然后seq生成一个客户端的随机数X

第二次:发送SNY=1,然后ack=客户端的seq+1(这样客户端收到后就能确认是之前想要连接的那个服务端),然后把服务端也生成一个代表自己的随机数seq=Y发给客户端。

第三次:ACK=1。 seq=客户端随机数+1,ack=服务端随机数+1(这样服务端就知道是刚刚那个客户端了)

为什么建立连接需要三次握手?
C端只有确定了自己能与S端连接上才能开始发数据。所以两次握手肯定是最基本的。

C端发了个连接请求消息到S端,S端收到后S端就知道自己与C端是可以连接成功的,所以S端接收到消息后得应答,C端得到S端的回复后,才能确定自己与S端是可以连接上的,这就是第二次握手。

第三次握手是为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误。

具体情况就是:

C端发出去的第一个网络连接请求由于某些原因在网络节点中滞留了,导致延迟,直到连接释放的某个时间点才到达S端,这是一个**早已失效的报文,**但是此时S端仍然认为这是C端的建立连接请求第一次握手,于是S端回应了C端,第二次握手。

如果只有两次握手,那么到这里,连接就建立了,但是此时C端并没有任何数据要发送,而S端就会傻傻的等待着,造成很大的资源浪费。所以需要第三次握手,只有C端再次回应一下,就可以避免这种情况。

四次挥手断开连接
在这里插入图片描述
服务端的ACK(回复客户端)和FIN(终止)消息并不是同时发出的,而是先ACK,然后再FIN,当客户端要求断开连接时,此时服务端可能还有未发送完的数据,所以先ACK,然后等数据发送完再FIN。这样就变成了四次握手了。

TCP通过滑动窗口协议提供可靠的传输
滑动窗口协议
发送窗口只有收到确认帧才会向后移动窗口继续发送其他帧。

一开始发送窗口在前3帧[1,2,3],则前3帧是可以发送的,后面的则暂时不可以发送,比如[1]帧发送出去后,收到了来自接收方的确认消息,则此时发送窗口才可以往后移1帧,发送窗口来到[2,3,4],同样只有发送窗口内的帧才可以被发送,一次类推。

而接收窗口接收到帧后将其放入对应的位置,然后移动接收窗口,接口窗口与发送窗口一样也有一个大小,如接收窗口是5帧,则落在接收窗口之外的帧会被丢弃。

发送窗口和接收窗口大小的不同设定就延伸出了不同的协议:

停止-等待协议:每发一帧都要等到确认消息才能发送下一帧,缺点:效率较差。

后退N帧协议:**接收方正确的接受到N帧后发一个累计确认消息给发送窗口,确认N帧已正确收到,如果发送方规定时间内未收到确认消息则认为超时或数据丢失,则会重新发送确认帧之后的所有帧。**缺点:出错序号后面的PDU已经发送过了,但是还是要重新发送,比较浪费。

选择重传协议:若出现差错,只重新传输出现差错涉及需要的PDU

由于发送窗口与接收窗口之间会存在发送效率和接收效率不匹配的问题,就会导致拥塞,解决这个问题TCP有一套流量控制和拥塞控制的机制。

流量控制和拥塞控制
1)流量控制:
流量控制是对一条通信路径上的流量进行控制,就是发送方通过获取接收方的回馈来动态调整发送的速率,来达到控制流量的效果,其目的是保证发送者的发送速度不超过接收者的接收速度。

2)拥塞控制:
拥塞控制是对整个通信子网的流量进行控制,属于全局控制。

① 慢开始+拥塞避免
在这里插入图片描述
一开始使用慢启动,即拥塞窗口设为1,然后拥塞窗口指数增长到慢开始的门限值(ssthresh=16),则切换为拥塞避免,即加法增长,这样增长到一定程度,导致网络拥塞,则此时会把拥塞窗口重新降为1,即重新慢开始,同时调整新的慢开始门限值为12

② 快重传+快恢复

快重传:快重传的设计思路是:如果发送方收到3个重复的接收方的ACK,就可以判断有报文段丢失,此时就可以立即重传丢失的报文段,而不用等到设置的超时时间到了才开始重传。

快恢复:上面的拥塞控制会在网络拥塞时将拥塞窗口降为1,重新慢开始,这样存在的一个问题就是网络无法很快恢复到正常状态。快恢复就是来优化这个问题的,使用快恢复,则出现拥塞时,拥塞窗口只会降低到新的慢开始门阀值(即12),而不会降为1,然后直接开始进入拥塞避免加法增长
在这里插入图片描述
快重传和快恢复是对拥塞控制的进一步改进。

猜你喜欢

转载自blog.csdn.net/u012124438/article/details/113791607