计网学习笔记
Posted 轻舟一曲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计网学习笔记相关的知识,希望对你有一定的参考价值。
计网复习
TCP和UDP区别
用户数据报协议UDP | 传输控制协议TCP |
---|---|
无连接,不可靠 | 面向连接,可靠 |
支持1对1,1对多,多对1,多对多通信 | 1对1,全双工通信 |
面向应用层报文,直接打包拆包 | 面向字节流,有序号 |
尽最大努力交付,不可靠,没有流量控制和拥塞避免适合媒体通信 | 可靠传输,使用流量控制和拥塞避免 |
首部开销仅8字节 | 首部最小20字节和最大60子节 |
TCP流量控制
发送方的发送速率大于接收方的接收速率严重的时候——》丢包;
流量控制(滑动窗口机制)——》控制发送方的发送速率。
利用可变窗口大小进行流量控制,设主机A向主机B发送数据(每个报文段长100字节),双方确定窗口值是400。
接收方进行了3次流量控制:
1)发送前200个字节后,201—300字节丢失,接收方返回确认ACK=200,并将窗口缩小为300;
2)发送方收到ACK=200,rwnd=300,滑动窗口右移200字节(可发送201-500字节,201-300已发送但还未确认),继续发送300-500后(接收方采用累积确认方式先缓存起来)不能再发送,此时201-300发生超时重传,接收方收到后返回确认ACK=500,并将窗口缩小为100;
3)发送方收到ACK=500,rwnd=100,滑动窗口右移300字节(可发送501-600字节),继续发送
501-600后不能再发送,接收方收到后返回确认ACK=600,并将窗口缩小为0;
4)发生方收到ACK=600,rwnd=0,滑动窗口右移100字节(不可再发送)。
流量控制有什么问题吗?
死锁问题
假设发送方的发送窗口都已经发送完毕但还没全部确认;
接收方返回确认的ACK和rwnd丢失(rwnd开始为0,但不久后接收方又有缓存所以赶紧发了400,但2个都丢失了);
此时发送方一直等待接收方的0窗口通知,而接收方也一直等待发送方的数据,形成死锁。
解决死锁
给每个TCP连接设置1个持续计时器;
接收方rwnd=0时候启动计时器,到期发送0窗口探测报文。
TCP拥塞避免
拥塞是什么?
某段时间对网络中的某一资源的需求超过了其供给能力从而导致网络的性能变差。
提高节点处理机的速度或者扩大结点缓存的存储空间能解决拥塞问题吗?
不能,网络拥塞往往是由许多因素引起的,比如系统各个部分的不平衡等。
拥塞控制和流量控制的差别?
拥塞问题是全局性问题:防止过多的数据注入到网络中导致网络中的路由器或链路过载,涉及到所有的主机、所有的路由器、以及与降低网络传输性能有关的所有因素。
流量控制是端到端的问题:控制发送端发送数据的速率,以便使接收端来得及接受。
介绍下4种拥塞控制算法?
-
慢开始 (并不是指速度慢而是刚开是注入网络的流量小,指数增加)
-
拥塞避免 (加法增加)
-
快重传 (报文段丢失立即发送冗余ACK)
-
快恢复 (收到3个重复ACK:ssth=rwnd/2
[如果处于慢开始阶段还要+3因为重传的那3个冗余ACK不算] )
慢开始算法只是在TCP连接建立时和网络出现超时时才使用。
发送窗口<=拥塞窗口;
防止cwnd增长过大引起网络拥塞,慢开始门限ssthresh
cwnd<ssthresh:慢开始算法。
cwnd>ssthresh:拥塞避免算法。
cwnd=ssthresh:慢开始与拥塞避免算法任意。
早期版本
在慢开始或者拥塞避免阶段,发送方判断网络拥塞(延时或者丢失导致没收到确认);
ssth=(拥塞避免时的)rwnd/2,然后)rwnd=1,执行慢开始;
迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
改进
等待超时重传的时间太长,浪费时间和资源;
快重传
- 采用立即确认和重复确认机制而不是捎带确认机制;
- 更早的重传丢失的报文段;
- 发送端收3个重复ACK时,则断定分组丢失;
- 立即重传丢失的报文段,而不必等待重传计时器超时。
快恢复
配合快重传使用。
-
发送端收3个重复ACK则判断分组丢失,乘法减小;
-
如果是超时重传:ssth=(拥塞时)rwnd/2 ,rwnd=1,执行慢开始;
-
如果是重传3次:ssth=(拥塞时)rwnd/2 +3 (因为重传的那3个冗余ACK不算。但是接下去并不执行慢开始算法),rwnd=ssth,执行拥塞避免。
DCTCP算法
补充:目前最流行的分布式算法(没有之一):Map-Reduce
-
map函数主要将所有数据按照key组织到一起;
-
reduce函数负责计算,将map返回后的数据进行详细处理
数据中心TCP算法,对TCP流量控制和拥塞避免的改进。
因为交换机是先储存后转发数据包,所以传统的解决冲突超时重发增加缓冲区的大小也必定会增加排队时延。
数据中心TCP算法:
接收方的缓冲区数据包的个数达到设定的某个数时,在返回包中加上ECN(显示通知拥塞);
发送方根据收到的ACK包的中ECN的比例来确定窗口减小的程度, 比例越高减小越大;
使得发送方动态调整发送速度,适应缓存区占用情况,而不是传统的等到丢包才有所动作,遇到拥塞就将窗口减半的策略。
性能提升:
- 缓冲区占用
- 短数据时延
- 大数据时延
- 吞吐量
TCP三次握手
三次握手示意图
三次握手概述:
-
首先Client端发送连接请求报文;
-
Server段接受连接后回复ACK报文,并为这次连接分配资源;
-
Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。
进行三次握手:
第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN=x。此时客户端处于 SYN_SENT 状态。
首部的同步位SYN=1,初始序号seq= x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN=y。同时会把客户端的 x+ 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 的状态。
在确认报文段中SYN=1,ACK=1,确认号ack=x+1(表示我已经收到客户端的x,期待下一个为x+1),seq= y。
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 y + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
确认报文段ACK=1,确认号ack=y+1(表示我已经收到服务器的y,期待下一个为y+1),序号seq=x+1(客户端下一个要发送的数据),ACK报文段可以携带数据,不携带数据则不消耗序号。
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
在socket编程中,客户端执行connect()时,将触发三次握手。
为什么连接的时候是三次,两次不行吗?
弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
第一次握手:客户端发送网络包,服务端收到了。
这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。
这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。
这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
为了防止 已失效的链接请求报文突然又传送到了服务端,因而产生错误。
试想如果是用两次握手,则会出现下面这种情况:
如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一值等待客户端发送数据,浪费资源。
什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
这里在补充一点关于SYN-ACK 重传次数的问题:
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
ISN(Initial Sequence Number)是固定的吗?
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
三次握手过程可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
如果第三次握手丢失,客户端会如何处理?
超时,断开连接。
SYN洪泛攻击是什么? DDOS攻击
客户端不断进行请求链接会怎样? DDos 攻击
- 服务器端会为每个请求创建一个链接;
- 服务器发送确认报文后等待客户端进行确认,但客户端一直不返回确认。
SYN洪泛攻击也属于DDOS攻击的一种。
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstat 命令来检测 SYN 攻击。
netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
- 缩短超时(SYN Timeout)时间
- 限制同时打开最大半连接数
- 过滤网关防护
- SYN cookies技术
TCP四次挥手
四次挥手示意图
四次挥手概述: 中断连接端可以是Client端,也可以是Server端
-
Client端发送FIN报文发起中断连接请求;
-
Server端发送ACK,Client端就进入FIN_WAIT状态;
-
Server端数据发完了,发送FIN报文;
-
Client端收到FIN报文后发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。
建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。
刚开始双方都处于ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下:
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。
第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
挥手为什么是四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
2MSL等待状态是什么?
TIME_WAIT状态也成为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。
对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。
这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口(客户的IP地址和端口号,服务器的IP地址和端口号)不能再被使用。这个连接只能在2MSL结束后才能再被使用。
四次挥手释放连接时为什么需要等待2MSL?
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
两个理由:
保证客户端发送的最后一个ACK报文段能够到达服务端。
这个ACK报文段有可能丢失,使得处于LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认,服务端超时重传FIN+ACK报文段,而客户端能在2MSL时间内收到这个重传的FIN+ACK报文段,接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务端都进入到CLOSED状态,若客户端在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到服务端重传的FIN+ACK报文段,所以不会再发送一次确认报文段,则服务端无法正常进入到CLOSED状态。
防止“已失效的连接请求报文段”出现在本连接中。
客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。
为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?
理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
Web页面请求过程
首先要有自己的IP地址,运行DHCP协议,从本地DHCP服务器获得一个IP地址以及其他信息。
DHCP获得本机IP地址
-
DHCP请求报文–>
UDP[源端口68,目的端口67]–>
IP广播[源IP地址0.0.0.0,目的IP地址255.255.255.255]–>
以太网帧广播[目的MAC地址FF.FF.FF.FF.FF.FF,源MAC地址];
-
交换机收到帧并进行广播;
-
路由器收到帧并解封装出DHCP请求;
-
路由器中的DHCP服务器以CIDR子网块分配IP地址;
-
DHCP ACK报文—>UDP—>IP—>以太网帧—>发给交换机;
- 分配的IP地址
- 子网块(即掩码)
- 默认网关路由器的IP地址
- DNS服务器的IP地址
-
交换机自学习,知道将该帧转发给目的MAC地址的主机;
-
主机收到帧解封装,记录请求得到的IP地址和DNS服务器的IP地址,IP转发表记录默认网关IP;
现在它可以上网了,当键入URL时www.google.com…
DNS获得目的IP地址
-
DNS查询报文—>
UDP[源端口,DNS服务器端口53]—>
IP[源IP地址,DNS服务器IP地址]—>
以太网帧(链路层寻址,默认网关MAC地址?)—>网关路由器- ARP地址解析;
- ARP查询报文->UDP->IP[源IP地址,默认网关IP地址]->以太网帧广播;
- 网关路由器收到帧,提取网关路由MAC地址响应;
- ARP应答->UDP[主机端口]->IP[主机IP地址]->以太网帧[主机MAC地址]->交换机->主机;
- 现在,主机得到网关路由器MAC地址,可以继续进行DNS查询了。
-
网关路由器抽取DNS服务器IP地址,根据转发表转发到DNS服务器所在局域网的网关路由器;
-
路由器收到帧抽取目的地址,根据转发表(已根据域内协议RIP,OSPF和域间协议BGP填写)转发到DNS服务器;
-
DNS服务器解封装后抽取DNS查询报文,找到对应域名的IP地址(缓存数据来源于goolgle.com的权威DNS服务器);
-
DNS应答报文->UDP->IP->网关路由器反向转发给主机;
-
现在目的IP地址终于找到了,可以访问目的IP对应的服务器了。
TCP建立请求连接
-
HTTP GET请求报文->
TCP套接字(TCP三次握手,第一次:生成80端口的SYN请求报文,转发过程域间链路转发的路由转发表项由BGP决定,第二次:服务器收到后进行响应,反向转发SYN ACK报文);
封装在IP,以太网帧转发;
服务器收到后响应HTTP,反向转发回去;
主机收到HTTP响应,从HTTP实体抽取Web网页并渲染显示。
输入 URL后
基本必问的问题了,因为这个问题能考察对计算机网络整体的掌握程度,以及方便面试官扩展问题
简要介绍
一般会经过一下几个过程:
- 首先,在浏览器地址栏输入url;
- 浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,,会直接在屏幕中显示页面的内容,若没有则调到第三步操作;
- 在发送http请求之前,需要域名DNS解析,解析获取相应的IP地址;
- 浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手;
- 握手成功后,浏览器向服务器发送http请求,请求数据包;
- 服务器处理收到的请求,将数据返回至浏览器;
- 浏览器收到http响应;
- 读取页面内容,渲染器渲染,解析html源码;
- 生成Dom树,解析css样式,js交互;
- 客户端和服务端交互;
- ajax查询。
步骤2的缓存查询:
- 浏览器缓存:浏览器会记录DNS一段时间,因此,只是第一个地方解析DNS请求;
- 操作系统缓存:如果在浏览器缓存中不包含这个记录,则会使系统调用操作系统,获取操作系统的记录(保存最近的DNS查询缓存);
- 路由器缓存:如果上述两个步骤均不能成功获取DNS记录,继续搜索路由器缓存;
- ISP:若上述均失败,继续向ISP搜索。
详细介绍 ,总体上分为六步
- 合成URL
- DNS域名解析
- 建立TCP连接,三次握手
- 发送HTTP请求,服务器处理请求,返回响应结果
- 关闭TCP连接,四次挥手
- 浏览器渲染
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cisMetDN-1624157412391)(https://i.loli.net/2021/06/20/augqw6P5cyEXDU2.png)]
DNS域名解析
在网络世界,你肯定记得住网站的名称,但是很难记住网站的 IP 地址,因而也需要一个地址簿,就是 DNS 服务器。DNS 服务器是高可用、高并发和分布式的,它是树状结构,如图:
- 根 DNS 服务器 :返回顶级域 DNS 服务器的 IP 地址
- 顶级域 DNS 服务器:返回权威 DNS 服务器的 IP 地址
- 权威 DNS 服务器 :返回相应主机的 IP 地址
DNS的域名查找,在客户端和浏览器,本地DNS之间的查询方式是递归查询;
在本地DNS服务器与根域及其子域之间的查询方式是迭代查询;
递归过程:
在客户端输入 URL 后,会有一个递归查找的过程,从浏览器缓存中查找->本地的hosts文件查找->找本地DNS解析器缓存查找->本地DNS服务器查找,这个过程中任何一步找到了都会结束查找流程。
如果本地DNS服务器无法查询到,则根据本地DNS服务器设置的转发器进行查询。若未用转发模式,则迭代查找过程如下图:
结合起来的过程,可以用一个图表示:
在查找过程中,有以下优化点:
DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
在域名和 IP 的映射过程中,给了应用基于域名做负载均衡的机会,可以是简单的负载均衡,也可以根据地址和运营商做全局的负载均衡。
建立TCP连接
首先,判断是不是https的,如果是,则HTTPS其实是HTTP + SSL / TLS 两部分组成,也就是在HTTP上又加了一层处理加密信息的模块。
服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。
进行三次握手,建立TCP连接。
第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
SSL握手过程
第一阶段 建立安全能力 包括协议版本 会话Id 密码构件 压缩方法和初始随机数
第二阶段 服务器发送证书 密钥交换数据和证书请求,最后发送请求-相应阶段的结束信号
第三阶段 如果有证书请求客户端发送此证书 之后客户端发送密钥交换数据 也可以发送证书验证消息
第四阶段 变更密码构件和结束握手协议
完成了之后,客户端和服务器端就可以开始传送数据。
备注
备注
ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0。TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1。
SYN(SYNchronization):在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
FIN(finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
发送HTTP请求,服务器处理请求,返回响应结果
关闭TCP连接
第一次挥手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次挥手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我"同意"你的关闭请求;
第三次挥手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
第四次挥手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
浏览器渲染
按照渲染的时间顺序,流水线可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、栅格化和显示。如图:
渲染进程将 HTML 内容转换为能够读懂DOM 树结构。
渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式。
创建布局树,并计算元素的布局信息。
对布局树进行分层,并生成分层树。
为每个图层生成绘制列表,并将其提交到合成线程。合成线程将图层分图块,并栅格化将图块转换成位图。
合成线程发送绘制图块命令给浏览器进程。浏览器进程根据指令生成页面,并显示到显示器上。
构建DOM树
浏览器从网络或硬盘中获得HTML字节数据后会经过一个流程将字节解析为DOM树,先将HTML的原始字节数据转换为文件指定编码的字符,然后浏览器会根据HTML规范来将字符串转换成各种令牌标签,如html、body等。最终解析成一个树状的对象模型,就是dom树。
具体步骤:
转码(Bytes -> Characters)—— 读取接收到的 HTML 二进制数据,按指定编码格式将字节转换为 HTML 字符串
Tokens 化(Characters -> Tokens)—— 解析 HTML,将 HTML 字符串转换为结构清晰的 Tokens,每个 Token 都有特殊的含义同时有自己的一套规则
构建 Nodes(Tokens -> Nodes)—— 每个 Node 都添加特定的属性(或属性访问器),通过指针能够确定 Node 的父、子、兄弟关系和所属 treeScope(例如:iframe 的 treeScope 与外层页面的 treeScope 不同)
构建 DOM 树(Nodes -> DOM Tree)—— 最重要的工作是建立起每个结点的父子兄弟关系
样式计算
渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
CSS 样式来源主要有 3 种,分别是通过 link 引用的外部 CSS 文件、style标签内的 CSS、元素的 style 属性内嵌的 CSS。
,其样式计算过程主要为:
可以看到上面的 CSS 文本中有很多属性值,如 2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。处理完成后再处理样式的继承和层叠,有些文章将这个过程称为CSSOM的构建过程。
页面布局
布局过程,即排除 script、meta
等功能化、非视觉节点,排除 display: none
的节点,计算元素的位置信息,确定元素的位置,构建一棵只包含可见元素布局树。如图:
其中,这个过程需要注意的是回流和重绘
。
生成分层树
页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree),如图:
如果你熟悉 PS,相信你会很容易理解图层的概念,正是这些图层叠加在一起构成了最终的页面图像。在浏览器中,你可以打开 Chrome 的"开发者工具",选择"Layers"标签。渲染引擎给页面分了很多图层,这些图层按照一定顺序叠加在一起,就形成了最终的页面。
并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。
栅格化
合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。如图:
通常一个页面可能很大,但是用户只能看到其中的一部分,我们把用户可以看到的这个部分叫做视口(viewport)。在有些情况下,有的图层可以很大,比如有的页面你使用滚动条要滚动好久才能滚动到底部,但是通过视口,用户只能看到页面的很小一部分,所以在这种情况下,要绘制出所有图层内容的话,就会产生太大的开销,而且也没有必要。
显示
最后,合成线程发送绘制图块命令给浏览器进程。
浏览器进程根据指令生成页面,并显示到显示器[即像素]上,渲染过程完成。
面试集锦
HTTP和HTTPS
TLS/SSL安全协议
TLS:传输层安全性协议;
SSL:TLS的前身;
为互联网通信提供安全及数据完整性保障。
HTTPS=HTTP+TLS/SSL
HTTP有信息窃听,篡改,劫持的风险。
TLS/SSL具有信息加密,完整性校验,身份验证的功能。
TLS/SSL依赖三类算法:
- 散列函数 Hash (验证信息的完整性)
- 对称加密 (密钥协商加密)
- 非对称加密 (密钥协商加密和身份认证)
散列函数 Hash
常见的有 MD5、SHA1;
单向不可逆、输入敏感、输出长度固定;
数据的任何修改都会改变散列函数的结果,用于防止信息篡改并验证数据的完整性。
对称加密和非对称加密介绍见下一个问题
TLS/SSL 基本工作方式:
- 客户端使用服务器公钥与服务器进行通信;
- 客户端使用自己私钥实现身份验证;
- 客户端与服务器协商对称加密使用的密钥;
- 服务器对信息以及信息摘要进行对称加密;
- 不同节点采用不同对称密钥,信息只能通信双方获取。
密钥协商过程中的问题?
首先服务器的公钥是怎么传递给客户端的呢?
这样是不安全的!!!
公钥欺骗进行信息劫持
- 服务器向客户端发送自己的公钥;
- 窃听者M在传输过程中将其修改为自己的公钥;
- 客户端拿到的是窃听者的公钥却误以为是服务器公钥;
- 这样,窃听者就可以扮演服务器的角色了。
如何解决公钥欺骗问题呢?
用私钥做签章验证即可。
证书颁发机构CA管理公钥基础设施 PKI。
PKI :创建、吊销、分发以及更新密钥对应证书的服务。
证书颁发机构通常采用层次(例如:根证书->中间证书->服务器证书)的签名构架。
- 服务器向CA申请证书;
- CA审核信息并签发证书给服务器(获得非对称秘钥,公钥加密,私钥解密,私钥签名,公钥验证);
- 服务器通信私钥签名返回给客户端;
- 客户端用服务器的公钥验证身份;
- 双方秘钥协商。
TLS/SSL 握手过程介绍
-
请求:客户端发起请求,以明文传输请求信息:
-
版本信息;
-
加密套件:
- 认证算法 (身份验证)
- 密钥交换算法 (密钥协商)
- 对称加密算法 (信息加密)
- 信息摘要 (完整性校验)
-
压缩算法;
-
随机数C:用于后续的密钥的生成,防止重放攻击(直接重传登录数据包的攻击)。
-
-
响应:服务器响应请求信息,并携带证书链,随机数S返回;
-
证书链签名过程
-
发送方用hash函数将从报文中生成报文摘要;
-
发送方用自己的私钥对摘要加密作为数字签名;
-
接收方用一样的hash函数接收报文中计算出报文摘要;
-
接收方用发送方的公钥来对报文附加的数字签名进行解密;
-
若接收方计算出来的报文摘要与解密出来的报文摘要相同,验证通过。
-
数字签名的2个功能:
- 确认是对方身份,因为对方签名唯一;
- 确定消息完整性,数字签名特点代表报文特征。
-
-
证书校验:
- 证书链可信性;
- 是否吊销;
- 有效期;
- 域名匹配。
-
秘钥协商:
- 随机数字P并用证书公钥加密,发送给服务器;
- 计算协商秘钥key=f(C,S,P);
- 通知服务器后续通信都使用协商秘钥进行通信;
- 将所有通信参数的hash采用协商秘钥加密打包发送。
-
服务器握手验证:
- 计算协商秘钥key=f(C,S,P);
- 接收所有通信参数的hash值并解密后与之前的参数验证是否一致;
- 通知客户端后续通信都使用协商秘钥进行通信;
- 将所有通信参数的hash采用协商秘钥加密打包发送。
-
客户端握手验证:
- 接收所有通信参数的hash值并解密后与之前的参数验证是否一致;
- 若一致,TSL/SSL握手完成。
-
双方使用协商秘钥加密通信。
HTTP
概述:
- 80端口;
HTTP
概述:
- 超文本传输协议;
- 明文传输;
- 无状态连接;
- 运行在TCP之上。
HTTPS
概述:
-
443端口;
-
Https运行在SSL上,SSL需要CA颁发的证书(收费滴);
-
SSL运行于TCP之上;
-
TSL/SSL握手;
-
数据完整性校验;
-
双向身份认证;
-
客户端发起 SSL 握手消息给服务端要求连接;
-
服务端将证书发送给客户端;
-
客户端(内置所有受信任 CA 的证书)检查确认证书是否可信;
-
Tips:
-
互联网有太多的服务需要使用证书来验证身份;
-
客户端无法内置所有证书,只有 CA 的根证书,;
-
需要通过服务器将以证书链的形式将证书发送给客户端;
-
-
服务端要求客户端发送证书,并检查是否通过验证。
-
-
加密传输(对称非对称混合加密):综合利用了非对称加密的安全性和对称加密的快速性。
-
客户端以明文传输发送协商信息,包括加密套件算法:
- 认证算法 (身份验证)
- 密钥交换算法 (密钥协商)
- 对称加密算法 (信息加密)
- 信息摘要算法 (完整性校验)
-
服务器响应请求信息,并携带签名和证书链返回;
-
证书校验;
-
秘钥协商;
-
服务器握手验证;
-
客户端握手验证;
-
双方使用协商秘钥加密通信。
HTTPS的优缺点
优点:
- 认证用户和服务器,确保数据正确发送;
- 防止数据在传输过程中不被窃取、修改,确保数据的完整性;
- 最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
缺点:
- TSL/SSL握手阶段费时,会使页面的加载时间延长;
- 连接缓存不如 HTTP 高效,会增加数据开销;
- 安全范围的有限,无法抵挡黑客攻击、拒绝服务攻击和服务器劫持;
- 复杂的算法占用一定的计算资源和服务器成本;
- SSL 证书的信用链体系并不安全,中间人控制 CA 根证书。
对称加密和非对称加密
对称密钥加密
概述:双方商定加密解密使用同一个密钥;
特点:算法公开、计算量小、加密速度快、加密效率高;
问题:泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密。
非对称秘钥加密
概述:
- A生成一对密钥并将公钥对外公开;
- 需要向A发消息的B使用A的公钥加密后再发送给A;
- A收到后用自己的私钥解密;
- A想回复B正好相反。
验证:
- A传资料给B时,用自己的私钥做签章;
- B用A的公钥来验章,确认讯息是由 A 发的。
特点:
- 私钥可生成公钥,但公钥无法倒推私钥;
- 公钥加密,私钥解密;
- 私钥签名,公钥验证;
- 消除了双方交换密钥的需要。
问题:算法强度复杂,加密解密速度慢。
TCP如何保证可靠性
TCP提供一种面向连接的、可靠的字节流服务。
- 数据包校验:CRC冗余校验,校验和检测数据在传输过程中的变化;
- 报文排序:数据在传输过程乱序,交给上层的数据应该是要有序的;
- ACK确认:接收方收到帧或回复ACK确认;
- 冗余ACK保证有序;
- 选择重传机制;
- 超时重发:发送方发送报文后启动定时器,若超时还未收到ACK确认,重发;
- 丢弃重复数据;
- 拥塞避免和流量控制:可变大小的滑动窗口协议。
Get与POST
-
URL参数可见性
-
GET可见:请求数据放在URL即HTTP协议头上,?分割URL和传输数据,&连接参数;
-
POST不可见:请求数据放在HTTP的包体内Requrest Body;
-
-
传输数据大小
-
GET:不超过2k-4k;
- 原则上URL长度无限制;
- 限制实际上取决于浏览器;
- 即使服务器最多处理64K大小的URL也没用.
-
POST:可以无限制,根据php.ini 配置文件设定;
-
-
传输数据方式
- GET:拼接URL进行传递参数,发1次TCP数据包:
- POST:Body体传输参数,发2次TCP数据包:
GET比POST更快
当然,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。
POST请求包含更多的请求头:多了首部字段content-type描述body部分包含的数据;
POST需要发2次TCP数据包:
-
POST请求过程
-
浏览器请求TCP连接(第一次握手);
-
服务器答应进行TCP连接(第二次握手);
-
浏览器确认并第1次发送数据:较小的POST请求头(第三次握手);
-
服务器返回100 Continue响应;
-
浏览器确认并第2次发送数据:DATA;
-
服务器返回200 ok响应 。
-
-
GET请求过程
- 浏览器请求TCP连接(第一次握手);
- 服务器答应进行TCP连接(第二次握手);
- 浏览器确认并发送全部数据:get报文比较小(第三次握手);
- 服务器返回200 ok响应 。
-
页面后退反应
- GET:不产生影响;
- POST:重新提交请求;
-
缓存
-
GET
-
可以缓存;
-
请求会被浏览器主动cache
-
-
POST
-
不可以缓存;
-
请求不会被浏览器主动cache,除非手动设置;
-
-
-
安全性
-
都不安全,原则上post肯定要比get安全毕竟传输参数时url不可见。
-
get请求的数据浏览器会缓存。
-
post请求的数据也可以通过抓包获得。
-
post那么好为什么还用get?get效率高。
-
-
GET请求只能进行url编码,而POST支持多种编码方式;
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留;
-
GET只接受ASCII字符的参数的数据类型,而POST没有限制。
-
GET一般用于搜索排序和筛选之类的操作,读取数据,而POST用于修改和写入数据;
Tips:HTTP状态码
-
状态码1xx:请
- 求处理中;
- 请求已被接受;
- 正在处理;
-
状态码2xx:
- 请求成功200 OK;
- 请求被成功处理 ;
-
状态码3xx:
- 重定向;
- 要完成请求必须进行进一步处理 ;
- 301 : 永久性转移 ;
- 302 :暂时性转移 ;
- 304 : 已缓存;
-
状态码4xx:
- 客户端错误;
- 请求不合法 ;
- 400:Bad Request,请求有语法问题 ;
- 403:拒绝请求 ;
- 404:客户端所访问的页面不存在;
-
状态码5xx:
- 服务器端错误;
- 服务器不能处理合法请求 ;
- 500 :服务器内部错误 ;
- 503 : 服务不可用,稍等 。
Session,Cookie,Application
状态保持的引入:
- 登录一个网站时常常会涉及到用户登录的状态保持,从而获得更好用户的体验;
- cookie和sessio就是用来实现状态保持的。
状态保持的原理:
-
用户登录向服务器发送post请求;
-
服务器接收请求,检验请求参数无误后,处理登录业务逻辑;
-
服务器生成sessionid放入cookie中,响应到前端浏览器;
-
浏览器本地保存cookie值;
-
用户再向服务器发送请求,把请求的网址连同该Cookie一同提交给服务器;
-
服务器收到请求,提取请求参数中的cookie,以此来辨认用户状态;
- 将获取的cookie值跟之前服务器生成的cookie比较;
- 若cookie值相同,则默认时同一个用户访问服务器;
- 从而实现用户登录状态保持。
Session概念:
-
称为会话控制;
-
存储特定用户会话所需的属性及配置信息;
-
Web页面跳转,用户Session对象中的变量不会丢失,一直存在;
-
用户请求 Web页,如果还没有会话,则服务器自动创建一个 Session对象;
-
Session运作流程
-
客户端请求服务器;
-
服务器若需记录该用户状态,就获取Session来保存状态;
-
如果服务器已创建过该用户session,就按照sessionid取出使用;
-
如果客户端请求没有sessionid,服务器创建一个session并生成关联sessionid;
-
将sessionid返回给客户端保存(可用 cookie);
- 若浏览器禁用Cookie,URL重写机制将sessionid传回服务器。
-
-
-
当会话过期或被放弃后,服务器终止该会话;
-
Session 对象最常见的一个用法就是存储用户的首选项(例如用户指明不喜欢查看图形)
Cookie概念:
-
保存在客户机中的由“名/值”对和其可选属性组成的小型文本文件;
-
网站为了辨别用户身份,进行Session跟踪储存在用户本地终端上的数据(经过加密);
-
Cookie运作流程
- 客户端请求服务器;
- 服务器若需记录该用户状态,用response向客户端浏览器颁发一个Cookie;
- 客户端浏览器会把Cookie保存起来;
- 客户端浏览器再请求该网站时,把请求的网址连同该Cookie一同提交给服务器;
- 服务器检查该Cookie,以此来辨认用户状态;
- 服务器还可以根据需要修改Cookie的内容。
-
-
客户端计算机暂时或永久保存的信息;
Cookie和Session对比
-
Cookie和Session都是客户端与服务器之间保持状态的解决方案:
-
Cookie在客户端保持;
-
Session在服务器保持;
-
-
实现机制
- Session的实现常常依赖于Cookie机制;
- 通过Cookie机制回传SessionID;
- 都是基于键值对的,session中保存的是对象,cookie中保存的是字符串;
- 都由后端服务器生成的;
- Session的实现常常依赖于Cookie机制;
-
大小限制:
- Cookie有大小限制;
- 浏览器对每个站点也有cookie的个数限制;
- Session没有大小限制;
- Session大小理论上只与服务器的内存大小有关;
-
安全性:
- Cookie存在安全隐患;
- 通过拦截或本地文件找到cookie后可以进行攻击;
- Session由于保存在服务器端,相对更加安全;
- Cookie存在安全隐患;