从浏览器地址栏输入 url 到显示主页的过程?
DNS 解析:将域名解析成对应的 IP 地址。
TCP 连接:与服务器通过三次握手,建立 TCP 连接
向服务器发送 HTTP 请求
服务器处理请求,返回 HTTp 响应
浏览器解析并渲染页面
断开连接:TCP 四次挥手,连接结束
说说 HTTP 常用的状态码及其含义?
说说 HTTP 与 HTTPS 有哪些区别?
HTTP 是超⽂本传输协议,信息是明⽂传输,存在安全⻛险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP ⽹络层之间加⼊了 SSL/TLS 安全协议,使得报⽂能够加密传输。
HTTP 连接建⽴相对简单, TCP 三次握⼿之后便可进⾏ HTTP 的报⽂传输。⽽ HTTPS 在 TCP 三次握⼿之后,还需进⾏ SSL/TLS 的握⼿过程,才可进⼊加密报⽂传输。
HTTP 的端⼝号是 80,HTTPS 的端⼝号是 443。
HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的
为什么要用 HTTPS?解决了哪些问题?
窃听 篡改 冒充
所以引入了 HTTPS,HTTPS 在 HTTP 与 TCP 层之间加⼊了 SSL/TLS 协议,可以很好的解决了这些风险:
信息加密:交互信息⽆法被窃取。
校验机制:⽆法篡改通信内容,篡改了就不能正常显示。
身份证书:能证明淘宝是真淘宝。
1. 混合加密
通过混合加密的方式可以保证信息的机密性,解决了窃听的风险。
HTTPS 采用的是对称加密和非对称加密结合的「混合加密」方式:
在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
采用「混合加密」的方式的原因:
对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。
非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
2. 摘要算法 + 数字签名
3. 数字证书
CA 签发证书的过程,如上图左边部分:
首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程,如上图右边部分:
首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
HTTPS工作流程是怎样的?
那现在来说一下HTTPS 主要工作流程:
客户端发起 HTTPS 请求,连接到服务端的 443 端口。
服务端有一套数字证书(证书内容有公钥、证书颁发机构、失效日期等)。
服务端将自己的数字证书发送给客户端(公钥在证书里面,私钥由服务器持有)。
客户端收到数字证书之后,会验证证书的合法性。如果证书验证通过,就会生成一个随机的对称密钥,用证书的公钥加密。
客户端将公钥加密后的密钥发送到服务器。
服务器接收到客户端发来的密文密钥之后,用自己之前保留的私钥对其进行非对称解密,解密之后就得到客户端的密钥,然后用客户端密钥对返回数据进行对称加密,酱紫传输的数据都是密文啦。
服务器将加密后的密文返回到客户端。
客户端收到后,用自己的密钥对其进行对称解密,得到服务器返回的数据。
说说 Session 和 Cookie 有什么联系和区别?
存储位置不一样,Cookie 保存在客户端,Session 保存在服务器端。
存储数据类型不一样,Cookie 只能保存 ASCII,Session 可以存任意数据类型,一般情况下我们可以在 Session 中保持一些常用变量信息,比如说 UserId 等。
有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般有效时间较短,客户端关闭或者 Session 超时都会失效。
隐私策略不同,Cookie 存储在客户端,比较容易遭到不法获取,早期有人将用户的登录名和密码存储在 Cookie 中导致信息被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。
存储大小不同, 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie。
TCP组成
TCP与UDP的区别
1. 连接
TCP 是面向连接的传输层协议,传输数据前先要建立连接。
UDP 是不需要连接,即刻传输数据。
2. 服务对象
TCP 是一对一的两点服务,即一条连接只有两个端点。
UDP 支持一对一、一对多、多对多的交互通信
3. 可靠性
TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。
UDP 是尽最大努力交付,不保证可靠交付数据。但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议,具体可以参见这篇文章:如何基于 UDP 协议实现可靠传输?(opens new window)
4. 拥塞控制、流量控制
TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
5. 首部开销
TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。
UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
6. 传输方式
TCP 是流式传输,没有边界,但保证顺序和可靠。
UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
TCP 是如何保证连接的可靠性的?
连接管理:TCP使用三次握手和四次挥手保证可靠地建立连接和释放连接,这里就不用多说了。
校验和:TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果接收端的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
序列号/确认应答:TCP 给发送的每一个包进行编号,接收方会对收到的包进行应答,发送方就会知道接收方是否收到对应的包,如果发现没有收到,就会重发,这样就能保证数据的完整性。就像老师上课,会问一句,这一章听懂了吗?没听懂再讲一遍。
流量控制:TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。(TCP 利用滑动窗口实现流量控制)
超时重传:超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被认为是丢包了,需要重传。
拥塞控制:如果网络非常拥堵,此时再发送数据就会加重网络负担,那么发送的数据段很可能超过了最大生存时间也没有到达接收方,就会产生丢包问题。为此TCP引入慢启动机制,先发出少量数据,就像探路一样,先摸清当前的网络拥堵状态后,再决定按照多大的速度传送数据。
详细说一下 TCP 的三次握手机制
最开始,客户端和服务端都处于 CLOSE 状态,服务端监听客户端的请求,进入 LISTEN 状态
客户端端发送连接请求,第一次握手 (SYN=1, seq=x),发送完毕后,客户端就进入 SYN_SENT 状态
服务端确认连接,第二次握手 (SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端就进入 SYN_RCV 状态。
客户端收到服务端的确认之后,再次向服务端确认,这就是第三次握手 (ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态。
为了保证数据能到达目标,TCP采用三次握手策略:
发送端首先发送一个带SYN(synchronize)标志的数据包给接收方【第一次的seq序列号是随机产生的,这样是为了网络安全,如果不是随机产生初始序列号,黑客将会以很容易的方式获取到你与其他主机之间的初始化序列号,并且伪造序列号进行攻击】
接收端收到后,回传一个带有SYN/ACK(acknowledgement)标志的数据包以示传达确认信息【SYN 是为了告诉发送端,发送方到接收方的通道没问题;ACK 用来验证接收方到发送方的通道没问题】
最后,发送端再回传一个带ACK标志的数据包,代表握手结束若在握手某个过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包
为什么要三次挥手
为了防止服务器端开启一些无用的连接增加服务器开销
如果服务器端就直接创建了这个连接并返回包含 SYN、ACK 和 Seq 等内容的数据包给客户端,这个数据包因为网络传输的原因丢失了,丢失之后客户端就一直没有接收到服务器返回的数据包。
如果没有第三次握手告诉服务器端客户端收的到服务器端传输的数据的话,服务器端是不知道客户端有没有接收到服务器端返回的信息的。
服务端就认为这个连接是可用的,端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。这样一来,就会有很多无效的连接端口白白地开着,导致资源的浪费。
防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
三次握手中每一次没收到报文会发生什么情况?
第一次握手服务端未收到 SYN 报文
服务端不会进行任何的动作,而客户端由于一段时间内没有收到服务端发来的确认报文,等待一段时间后会重新发送 SYN 报文,如果仍然没有回应,会重复这个过程,直到发送次数超过最大重传次数限制,就会返回连接建立失败。
第二次握手客户端未收到服务端响应的 ACK 报文
客户端会继续重传,直到次数限制;而服务端此时会阻塞在 accept()处,等待客户端发送 ACK 报文
第三次握手服务端为收到客户端发送过来的 ACK 报文
服务端同样会采用类似客户端的超时重传机制,如果重试次数超过限制,则 accept()调用返回-1,服务端建立连接失败;而此时客户端认为自己已经建立连接成功,因此开始向服务端发送数据,但是服务端的 accept()系统调用已经返回,此时不在监听状态,因此服务端接收到客户端发送来的数据时会发送 RST 报文给客户端,消除客户端单方面建立连接的状态
第二次握手传回了 ACK,为什么还要传回 SYN?
ACK 是为了告诉客户端传来的数据已经接收无误。
而传回 SYN 是为了告诉客户端,服务端响应的确实是客户端发送的报文
TCP三次握手中,最后一次回复丢失,会发生什么?
此时服务器还处于syn_recv状态 他会 3 6 12秒发送一次syn + ack包 以便客户端重新发送ack
如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server(服务端)自动关闭这个连接
四次挥手
数据传输结束之后,通信双方都可以主动发起断开连接请求,这里假定客户端发起
客户端发送释放连接报文,第一次挥手 (FIN=1,seq=u),发送完毕后,客户端进入 FIN_WAIT_1 状态。
服务端发送确认报文,第二次挥手 (ACK=1,ack=u+1,seq =v),发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态。
服务端发送释放连接报文,第三次挥手 (FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个 ACK。
客户端发送确认报文,第四次挥手 (ACK=1,seq=u+1,ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT 状态,等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
为什么要四次挥手
再来回顾下四次挥手双方发 FIN 包的过程,就能理解为什么需要四次了。
关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次
TCP 四次挥手过程中,为什么需要等待 2MSL, 才进入 CLOSED 关闭状态?
1. 为了保证客户端发送的最后一个 ACK 报文段能够到达服务端。 这个 ACK 报文段有可能丢失,因而使处在 LAST-ACK 状态的服务端就收不到对已发送的 FIN + ACK 报文段的确认。服务端会超时重传这个 FIN+ACK 报文段,而客户端就能在 2MSL 时间内(超时 + 1MSL 传输)收到这个重传的 FIN+ACK 报文段。接着客户端重传一次确认,重新启动 2MSL 计时器。最后,客户端和服务器都正常进入到 CLOSED 状态。
2. 防止已失效的连接请求报文段出现在本连接中。客户端在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。
客户端 TIME-WAIT 状态过多会产生什么后果?怎样处理?
严重消耗着服务器的资源,此时部分客户端就会显示连接不上
会大量消耗的Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法在发起新的连接了
解决办法:
用负载均衡来抗这些高并发的短请求;
服务器可以设置 SO_REUSEADDR 套接字选项来避免 TIME_WAIT状态,TIME_WAIT 状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的
强制关闭,发送 RST 包越过TIMEWAIT状态,直接进入CLOSED状态
服务器出现了大量 CLOSE_WAIT 状态如何解决?
大量 CLOSE_WAIT 表示程序出现了问题,对方的 socket 已经关闭连接,而我方忙于读或写没有及时关闭连接,需要检查代码,特别是释放资源的代码,或者是处理请求的线程配置。
TCP流量控制
TCP 提供了一种机制,可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是流量控制。
TCP 通过滑动窗口来控制流量,我们看下简要流程:
首先双方三次握手,初始化各自的窗口大小,均为 400 个字节。
假如当前发送方给接收方发送了 200 个字节,那么,发送方的 SND.NXT 会右移 200 个字节,也就是说当前的可用窗口减少了 200 个字节。
接受方收到后,放到缓冲队列里面,REV.WND =400-200=200 字节,所以 win=200 字节返回给发送方。接收方会在 ACK 的报文首部带上缩小后的滑动窗口 200 字节
发送方又发送 200 字节过来,200 字节到达,继续放到缓冲队列。不过这时候,由于大量负载的原因,接受方处理不了这么多字节,只能处理 100 字节,剩余的 100 字节继续放到缓冲队列。这时候,REV.WND = 400-200-100=100 字节,即 win=100 返回发送方。
发送方继续发送 100 字节过来,这时候,接收窗口 win 变为 0。
发送方停止发送,开启一个定时任务,每隔一段时间,就去询问接受方,直到 win 大于 0,才继续开始发送。
TCP滑动窗口
TCP 滑动窗口分为两种: 发送窗口和接收窗口。发送端的滑动窗口包含四大部分,如下:
已发送且已收到 ACK 确认
已发送但未收到 ACK 确认
未发送但可以发送
未发送也不可以发送
接收方的滑动窗口包含三大部分,如下:
已成功接收并确认
未收到数据但可以接收
未收到数据并不可以接收的数据
拥塞控制
慢启动算法
它表示 TCP 建立连接完成后,一开始不要发送大量的数据,而是先探测一下网络的拥塞程度。由小到大逐渐增加拥塞窗口的大小,如果没有出现丢包,每收到一个 ACK,就将拥塞窗口 cwnd 大小就加 1(单位是 MSS)。每轮次发送窗口增加一倍,呈指数增长,如果出现丢包,拥塞窗口就减半,进入拥塞避免阶段。
拥塞避免
一般来说,慢启动阀值 ssthresh 是 65535 字节,cwnd到达慢启动阀值后
每收到一个 ACK 时,cwnd = cwnd + 1/cwnd
当每过一个 RTT 时,cwnd = cwnd + 1
显然这是一个线性上升的算法,避免过快导致网络拥塞问题。
接着上面慢启动的例子,假定 ssthresh 为 8 ::
当 8 个 ACK 应答确认到来时,每个确认增加 1/8,8 个 ACK 确认 cwnd ⼀共增加 1,于是这⼀次能够发送 9 个 MSS ⼤⼩的数据,变成了线性增⻓。
拥塞发生
快速重传
拥塞窗口大小 cwnd = cwnd/2
慢启动阀值 ssthresh = cwnd
进入快速恢复算法
快速恢复
cwnd = sshthresh + 3
重传重复的那几个 ACK(即丢失的那几个数据包)
如果再收到重复的 ACK,那么 cwnd = cwnd +1
如果收到新数据的 ACK 后, cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入了拥塞避免的算法了。
可以简单说一下TCP 的重传机制吗?
重传包括超时重传、快速重传、带选择确认的重传(SACK)、重复 SACK 四种。
说说 TCP 的粘包和拆包?
要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包;
接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;
要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包;
待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。即 TCP 报文长度 - TCP 头部长度 > MSS。
解决
发送端将每个数据包封装为固定长度
在数据尾部增加特殊字符进行分割
将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小。
DNS的解析过程
首先通过游览器缓存判断有没有这个ip 有就返回
本地dns查找 有就返回
根域名服务器查找
顶级域名查找 com
权限域名查找
说下 HTTP/1.0,1.1,2.0 的区别?
关键需要记住 HTTP/1.0 默认是短连接,可以强制开启,HTTP/1.1 默认长连接,HTTP/2.0 采用多路复用。
HTTP/1.0
默认采用的是短连接的连接方式,每次请求都需要建立一个 TCP 连接。它可以设置 Connection:keep-alive 这个字段,强制开启长连接。
HTTP/1.1
引入了持久化连接的概念:与 HTTP/1.0 的TCP 连接方式(每次请求都需要建立一个 TCP 连接不同),其 TCP 连接默认不关闭,可以被多个请求复用。
分块传输编码:即服务端每产生一块数据,就发送一块的数据,用” 流模式” 替代了” 缓存模式”。
管道机制:在同一个 TCP 连接里面,客户端可以同时发送多个请求给服务端
HTTP / 2 存在的一些不足
建立连接时间长,没办法,谁让它爸是TCP呢?我们知道,TCP三次握手的过程客户端和服务端之间需要交互三次,也就是说需要消耗1.5RTT,还有TLS加密握手,所以大概需要3RTT左右。而具体消耗的时长根据服务器和客户端之间的距离则不尽相同,如果比较近的话,消耗在100ms以内,对于用来说可能没什么感知,但是如果一个RTT的耗时达到300-400ms,那么,一次连接建立过程总耗时可能要达到一秒钟左右,这时候,用户就会明显的感知到网页加载很慢。
队头阻塞问题。这里有同学会问,http2 不是解决了队头阻塞的问题吗?这里只说对了一半,http2 只解决了http消息队头阻塞问题,并没有解决TCP队头阻塞问题。
但是,对于管道连接还是有一定的限制和要求的,其中一个比较关键的就是服务端必须按照与请求相同的顺序回送HTTP响应。
这也就意味着,如果一个响应返回发生了延迟,那么其后续的响应都会被延迟,直到队头的响应送达。这就是所谓的HTTP队头阻塞。
HTTP队头阻塞问题在HTTP2中得到了很好的解决,HTTP2废弃了管道化大的方式,而引入帧、消息和数据流的概念,客户端和服务端可以把HTTP消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。
http2 虽然很好的解决了HTTP队头阻塞的问题。但是http2仍然会存在TCP队头阻塞的问题,因为http2还是基于TCP协议实现的。
TCP传输过程中会把数据拆分成一个一个小的有序的数据包,然后经过路由器、集线器、交换机等中间设备转发,最终到达目的地。如果其中某一个数据包没有按序到达,接收端就会保持连接等待数据包返回。这时就会阻塞后续的请求,就造成了TCP队头阻塞
因为HTTP/2的多路复用技术使得多个请求其实是基于同一个TCP连接的,如果某一个请求造成了TCP队头阻塞,那么多个请求都会受到影响。
HTTP3
HTTP/3主要有这些特点:
使用UDP作为传输层进行通信
在UDP的基础上QUIC协议保证了HTTP/3的安全性,在传输的过程中就完成了TLS加密握手
HTTPS 要建⽴⼀个连接,要花费 6 次交互,先是建⽴三次握⼿,然后是 TLS/1.3 的三次握⼿。QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互合并成了 3 次,减少了交互次数。
QUIC 有⾃⼰的⼀套机制可以保证传输的可靠性的。当某个流发⽣丢包时,只会阻塞这个流,其他流不会受到影响。
QUIC 协议有什么特点?
基于UDP的传输层协议:它使用UDP端口号来识别指定机器上的特定服务器。
可靠性:虽然UDP是不可靠传输协议,但是QUIC在UDP的基础上做了些改造,使得他提供了和TCP类似的可靠性。它提供了数据包重传、拥塞控制、调整传输节奏以及其他一些TCP中存在的特性。
实现了无序、并发字节流:QUIC的单个数据流可以保证有序交付,但多个数据流之间可能乱序,这意味着单个数据流的传输是按序的,但是多个数据流中接收方收到的顺序可能与发送方的发送顺序不同!
快速握手:QUIC提供0-RTT和1-RTT的连接建立
使用TLS 1.3传输层安全协议:与更早的TLS版本相比,TLS 1.3有着很多优点,但使用它的最主要原因是其握手所花费的往返次数更低,从而能降低协议的延迟。
UDP
UDP 协议为什么不可靠?
UDP 在传输数据之前不需要先建立连接,远地主机的运输层在接收到 UDP 报文后,不需要确认,提供不可靠交付。总结就以下四点:
不保证消息交付:不确认,不重传,无超时
不保证交付顺序:不设置包序号,不重排,不会发生队首阻塞
不跟踪连接状态:不必建立连接或重启状态机
不进行拥塞控制:不内置客户端或网络反馈机制
评论区