大家好,我是温大大
最近温大大又又又整理了:万字网络协议方面的总结
主要覆盖:网络基础、TCP/UDP 高频面试题、HTTP 协议、Cookis/session、滑动窗口机制等知识点。
这次「网络八股文」配合前两次
这样同学们的基础八股文算是覆盖全了:数据库、Linux、网络 就像凑齐七龙珠能召唤 1 个神龙许愿 1 个愿望一样,如果你好好的阅读下温大大这三篇文章, 保证你能实现「涨薪」愿望呀。
温大大的肝算是快到爆穿了,只求各位同学帮忙一键三连:点赞、在看、转发
目录
OSI 七层模型:
应用层:为应用程序提供网络服务;
表示层:数据格式转换、数据压缩和数据加密;
会话层:建立、断开和维护通信链接;
传输层:为上层协议提供端到端的可靠传输;
网络层:寻址和路由;
数据链路层:定义通过通信媒介互连的设备之间传输的规范;
物理层:利用物理传输介质为数据链路层提供物理连接。
TCP 五层模型:
面向有连接
面向无连接型
相同:
区别:
FTP:文件传输协议; SSH:远程登录协议; HTTP:web 服务器传输超文本到本地浏览器的超文本传输协议。 UDP 对应的典型的应用层协议:
DNS:域名解析协议; TFTP:简单文件传输协议; SNMP:简单网络管理协议。
三次握手大概就是这么个过程。
至此,完成了握手过程,A 知道 B 能收能发,B 知道 A 能收能发,通信连接至此建立。 三次连接是保证可靠的最小握手次数,再多次握手也不能提高通信成功的概率,反而浪费资源。
备注:
第一次握手:
总结:A 发(SYN=1,seq=x)到 B
第二次握手:
总结:B 发(SYN=1, ACK=1, seq=y, ack=x+1)到 A
第三次握手:
不可以。
防止已失效的连接请求报文段突然又传输到了服务端,导致产生问题。
比如客户端 A 发出连接请求,可能因为网络阻塞原因,A 没有收到确认报文,于是 A 再重传一次连接请求。
连接成功,等待数据传输完毕后,就释放了连接。
然后 A 发出的第一个连接请求等到连接释放以后的某个时间才到达服务端 B,此时 B 误认为 A 又发出一次新的连接请求,于是就向 A 发出确认报文段。
那为什么需要四次挥手呢?请看如下过程:
A 向 B 发起请求,表示 A 没有数据要发送了:A——>B;
B 向 A 发送信号,确认 A 的断开请求:B——>A;
B 向 A 发送信号,请求断开连接,表示 B 没有数据要发送了:B——>A;
A 向 B 发送确认信号,同意断开:A——>B。
B 收到确认信号,断开连接,而 A 在一段时间内没收到 B 的信号,表明 B 已经断开了,于是 A 也断开了连接。至此,完成挥手过程。
可能有捧油会问,为什么 2、3 次挥手不能合在一次挥手中?那是因为此时 A 虽然不再发送数据了,但是还可以接收数据,B 可能还有数据要发送给 A,所以两次挥手不能合并为一次。
挥手次数比握手多一次,是因为握手过程,通信只需要处理连接。而挥手过程,通信需要处理数据 + 连接。
保证 A 发送的最后一个 ACK 报文段能够到达 B。
防止已失效的连接请求报文段出现在本连接中。
短连接
长连接
长链接使用场景
短链接使用场景
区别 1: 解析协议不同
区别 2: HTTP2.0 采用多路复用 (Mutiplexing)
区别 3: http2.0 header 压缩:
区别 4: http2.0 服务端推送 (server push):
HTTPS 默认工作在 TCP 协议 443 端口,它的工作流程一般如以下方式:
1、客户端发起 HTTPS 请求
2、服务端的配置
采用 HTTPS 协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面 (startssl 就是个不错的选择,有 1 年的免费服务)。
这套证书其实就是一对公钥和私钥,如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。
3、传送证书
4、客户端解析证书
这部分工作是有客户端的 TLS 来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。
如果证书没有问题,那么就生成一个随机值,然后用证书对该随机值进行加密,就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。
5、传送加密信息
6、服务端解密信息
7、传输加密后的信息
8、客户端解密信息
简介
制作过程
浏览器验证过程
对称加密:通信双方使用相同的密钥进行加密。特点是加密速度快,但是缺点是密钥泄露会导致密文数据被破解。常见的对称加密有 AES 和 DES 算法。
非对称加密:它需要生成两个密钥,公钥和私钥。公钥是公开的,任何人都可以获得,而私钥是私人保管的。公钥负责加密,私钥负责解密;或者私钥负责加密,公钥负责解密。这种加密算法安全性更高,但是计算量相比对称加密大很多,加密和解密都很慢。常见的非对称算法有 RSA 和 DSA。
什么是 Cookie(客户端技术)
Cookie 实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用 response 向客户端浏览器颁发一个 Cookie。客户端会把 Cookie 保存起来。
当浏览器再请求该网站时,浏览器把请求的网址连同该 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容。
信息保存的时间可以根据需要设置.
如果没有设置 Cookie 失效日期,它们仅保存到关闭浏览器程序为止.
如果将 Cookie 对象的 Expires 属性设置为 Minvalue,则表示 Cookie 永远不会过期.
Cookie 存储的数据量很受限制,大多数浏览器支持最大容量为 4K,因此不要用来保存数据集及其他大量数据.
由于并非所有的浏览器都支持 Cookie,并且数据信息是以明文文本的形式保存在客户端的计算机中,
因此最好不要保存敏感的,未加密的数据,否则会影响网站的安全性
什么是 Session(服务端技术)
Session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 Session 保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是 Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。
每个用户访问服务器都会建立一个 session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个 SessionId。
1、数据存储位置:cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
2、安全性:cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗,考虑到安全应当使用 session。
3、服务器性能:session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用 cookie。
4、数据大小:单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
5、信息重要程度:可以考虑将登陆信息等重要信息存放为 session,其他信息如果需要保留,可以放在 cookie 中。
在 TCP 协议当中窗口机制分为两种:
1.固定的窗口大小
2.滑动窗口
固定窗口存在的问题
我们假设这个固定窗口的大小为 1,也就是每次只能发送一个数据,只有接收方对这个数据进行了确认后才能发送第二个数据。在图中我们可以看到,发送方每发送一个数据接收方就要给发送方一个 ACK 对这个数据进行确认。只有接收了这个确认数据以后发送方才能传输下个数据。
存在的问题:如果窗口过小,当传输比较大的数据的时候需要不停的对数据进行确认,这个时候就会造成很大的延迟。
如果窗口过大,我们假设发送方一次发送 100 个数据,但接收方只能处理 50 个数据,这样每次都只对这 50 个数据进行确认。发送方下一次还是发送 100 个数据,但接受方还是只能处理 50 个数据。这样就避免了不必要的数据来拥塞我们的链路。
因此,我们引入了滑动窗口
1.滑动窗口概述
滑动窗口通俗来讲就是一种流量控制技术。
它本质上是描述接收方的 TCP 数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据,如果发送方收到接收方的窗口大小为 0 的 TCP 数据报,那么发送方将停止发送数据,等到接收方发送窗口大小不为 0 的数据报的到来
2.工作原理
第一次发送数据这个时候的窗口大小是根据链路带宽的大小来决定的。
假设这时候的窗口是 3.这个时候接收方收到数据以后会对数据进行确认告诉哦发送方我下次希望收到的数据是多少。
在上图中:我们看到接收方发送的 ACK = 3(这是对发送方发送序列 2 的回答确认,下一次接收方期望接收到的是 3 序列信号),这个时候发送方收到这个数据以后就知道我第一次发送的 3 个数据对方只收到了两个,就知道第三个数据对方没有收到,下次返送的时候就从第 3 个数据开始发。这时候窗口大小就变为了 2.
看到接收方发送的 ACK 是 5 就表示他下一次希望收到的数据是 5,发送方就知道我刚才发送的 2 个数据对方收到了,这个时候开始发送第 5 个数据。
当链路变好或者变差,这个窗口还会发生变化,并不是第一次协商好了以后就永远不会变化了。
3.死锁状态
(1)概述:
(2)解决方法
4.TCP 报文段的发送时机(传输效率问题)
可以用以下三种不同的机制控制 TCP 报文段的发送时机:
(1)TCP 维持一个变量 MSS,等于最大报文段的长度。只要缓冲区存放的数据达到 MSS 字节时,就组装成了一个 TCP 报文段发送出去
(2)由发送方的应用进程指明要发送的报文段,即:TCP 支持推送操作
(3)发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去。
一、为何要进行拥塞控制?
为了方便,我们假设主机 A 给主机 B 传输数据。
我们知道,两台主机在传输数据包的时候,如果发送方迟迟没有收到接收方反馈的 ACK,那么发送方就会认为它发送的数据包丢失了,进而会重新传输这个丢失的数据包。
然而实际情况有可能此时有太多主机正在使用信道资源,导致网络拥塞了,而 A 发送的数据包被堵在了半路,迟迟没有到达 B。这个时候 A 误认为是发生了丢包情况,会重新传输这个数据包。
结果就是不仅浪费了信道资源,还会使网络更加拥塞。因此,我们需要进行拥塞控制。
二、如何知道网络的拥塞情况?
A 与 B 建立连接之后,就可以向 B 发送数据了,然而这个时候 A 并不知道此时的网络拥塞情况如何,也就是说,A 不知道一次性连续发送多少个数据包好,我们也把 A 一次性连续发送多少个数据包称之为拥塞窗口,用 N 代表此时拥塞窗口的大小吧。
为了探测网络的拥塞情况,我们可以采取以下两种策略:
1、先发送一个数据包试探下,如果该数据包没有发生超时事件 (也就是没有丢包)。那么下次发送时就发送 2 个,如果还是没有发生超时事件,下次就发送 3 个,以此类推,即 N = 1, 2, 3, 4, 5.....
2、一个一个增加实在是太慢了,所以可以刚开始发送 1 个,如果没有发生超时时间,就发送 2 个,如果还是没有发送超时事件就发送 4 个,接着 8 个...,用翻倍的速度类推,即 N = 1, 2, 4, 8, 16...
无论是第一种方法还是第二种方法,最后都会出现瓶颈值。不过这里值得注意的是,第一种情况的增长速率确实有点慢,但是第二种情况以指数增长,增长速度有点太快了,可能一下子就到瓶颈值了。
为了解决这个过慢或过快的问题,我们可以把第一种方法和第二种方法结合起来。也就是说,我们刚开始可以以指数的速度增长,增长到某一个值,我们把这个值称之为阈值吧,用变量 ssthresh 代替。当增长到阈值时,我们就不在以指数增长了,而是一个一个线性增长。
所以最终的策略是:前期指数增长,到达阈值之后,就以一个一个线性的速度来增长。
(注:8 之后其实是直线的,那里只是弯曲了一下)
我们也把指数增长阶段称之为慢启动,线性增长阶段称之为拥塞避免
三、到了瓶颈值之后怎么办? 无论是指数增长还是一个一个增长,最终肯定会出现超时事件,总不可能无限增长吧。当出现超时事件时,我们就认为此时网络出现了拥塞了,不能再继续增长了。我们就把这个时候的 N 的值称之为瓶颈值吧,用 MAX 这个字母来代替吧,即最大值。
注:这里再次提醒阈值过后是一个一个线性增长,图中之所以弯曲是因为我画图原因导致的
当达到最大值 MAX 之后,我们该怎么办呢?
当到达最大值之后我们采取的策略是这样的:
我们就回到最初的最初的状态,也就是说从 1,2,4,8.....开始,不过这个时候我们还会把 ssthresh 调小,调为 MAX 值的一半,即 ssthresh = MAX / 2。
图中阈值为 8,瓶颈值是 14;超时事件发生后,阈值为 14 / 2 = 7。
四、超时事件就一定是网络拥塞? 超时事件发送就一定是网络出现了拥堵吗?其实也有可能不是出现了网络拥堵,有可能是因为某个数据包出现了丢失或者损害了,导致了这个数据包超时事件发生了
为了防止这种情况,我们是通过冗余 ACK 来处理的。我们都知道,数据包是有序号的,如果 A 给 B 发送 M1, M2, M3, M4, M5...N 个数据包,如果 B 收到了 M1, M2, M4....却始终没有收到 M3,这个时候就会重复确认 M2,意在告诉 A,M3 还没收到,可能是丢失
当 A 连续收到了三个确认 M2 的 ACK,且 M3 超时事件还没发生。A 就知道 M3 可能丢失了,这个时候 A 就不必等待 M3 设置的计时器到期了,而是快速重传 M3。并且把 ssthresh 设置为 MAX 的一半,即 ssthresh = MAX/2,但是这个时候并非把控制窗口 N 设置为 1,而是让 N = ssthresh,N 在一个一个增长。
我们也把这种情况称之为快速恢复。而这种具有快速恢复的 TCP 版本称之为 TCP Reno。
还有另外一种 TCP 版本,无论是收到三个相同的 ACK 还是发生超时事件,都把拥塞窗口的大小设为 1,从最初状态开始,这种版本的 TCP 我们称之为 TCP Tahoe。
让拥塞窗口 cwnd 缓慢地增大,每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是加倍。这样拥塞窗口 cwnd 按线性规律缓慢增长。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限 ssthresh 设置为出现拥塞时的发送 方窗口值的一半(但不能小于 2)。然后把拥塞窗口 cwnd 重新设置为 1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。
有时个别报文段会在网络中丢失,但实际上网络并未发生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络发生了拥塞。这就导致发送方错误地启动慢开始,把拥塞窗口 cwnd 又设置为 1,因而降低了传输效率。
快重传算法可以避免这个问题。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认,使发送方及早知道有报文段没有到达对方。
发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约 20%。
当发送方连续收到三个重复确认,就会把慢开始门限 ssthresh 减半,接着把 cwnd 值设置为慢开始门限 ssthresh 减半后的数值,然后开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。
在采用快恢复算法时,慢开始算法只是在 TCP 连接建立时和网络出现超时时才使用。 采用这样的拥塞控制方法使得 TCP 的性能有明显的改进。
关注我,加我好友拉你进面试群,一起讨论面试干货 / 套路, 大家一起升职加薪,关注公众号:测试猿温大大