23、说说TCP为什么需要三次握手和四次握手
#一、三次握手
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包
主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备过程如下:
第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN©,此时客户端处于 SYN_SENT 状态
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,为了确认客户端的 SYN,将客户端的 ISN+1作为ACK的值,此时服务器处于 SYN_RCVD 的状态
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,值为服务器的ISN+1。此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接
上述每一次握手的作用如下:
第一次握手:客户端发送网络包,服务端收到了 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常
第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常
通过三次握手,就能确定双方的接收和发送能力是正常的。之后就可以正常通信了
#为什么不是两次握手?
如果是两次握手,发送端可以确定自己发送的信息能对方能收到,也能确定对方发的包自己能收到,但接收端只能确定对方发的包自己能收到 无法确定自己发的包对方能收到
并且两次握手的话, 客户端有可能因为网络阻塞等原因会发送多个请求报文,延时到达的请求又会与服务器建立连接,浪费掉许多服务器的资源#二、四次挥手
tcp
终止一个连接,需要经过四次挥手
过程如下:
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态,停止发送数据,等待服务端的确认第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态
第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态
#四次挥手原因
服务端在收到客户端断开连接Fin
报文后,并不会立即关闭连接,而是先发送一个ACK
包先告诉客户端收到关闭连接的请求,只有当服务器的所有报文发送完毕之后,才发送FIN
报文断开连接,因此需要四次挥手
#三、总结
一个完整的三次握手四次挥手如下图所示
#参考文献
24、清除浮动的方法(最常用的4种)
为什么要清除浮动?
清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题
1.如下,我给父盒子设置一个boder,内部放两个盒子一个big 一个small,未给big和small设置浮动,则他们会默认撑开父盒子
2.当我给内部两个盒子加上float属性的时候
顶部深蓝色盒子就会顶上来,然后父盒子因为没设置高度,变成一条线,big和small已经浮动了
总结一下:
当父元素不给高度的时候,
内部元素不浮动时会撑开
而浮动的时候,父元素变成一条线
这时候很多人会想到新建标签clear:both和float 方法,但是这两种方法并不推荐使用!
什么是clear:both
clear:both:本质就是闭合浮动, 就是让父盒子闭合出口和入口,不让子盒子出来
清除浮动的方法(最常用的4种)
1.额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear:both;)(不推荐)
big
small
额外标签法
此时
优点:通俗易懂,方便
缺点:添加无意义标签,语义化差
不建议使用。
2.父级添加overflow属性(父元素添加overflow:hidden)(不推荐)
通过触发BFC方式,实现清除浮动
.fahter{
width: 400px;
border: 1px solid deeppink;
overflow: hidden;
}
优点:代码简洁
缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素
不推荐使用
{
什么是BFC
BFC:块级格式化上下文,它是指一个独立的块级渲染区域,只有Block-level BOX参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与区域外部无关。
在一个Web页面的CSS渲染中,块级格式化上下文 (Block Fromatting Context)是按照块级盒子布局的。W3C对BFC的定义如下:
浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。
为了便于理解,我们换一种方式来重新定义BFC。一个HTML元素要创建BFC,则满足下列的任意一个或多个条件即可:
1、float的值不是none。
2、position的值不是static或者relative。
3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
4、overflow的值不是visible
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
怎么创建BFC
要显示的创建一个BFC是非常简单的,只要满足上述4个CSS条件之一就行。例如:
<div class="container"> 你的内容 </div>
1、display: table 可能引发响应性问题
2、overflow: scroll 可能产生多余的滚动条
3、float: left 将把元素移至左侧,并被其他元素环绕
4、overflow: hidden 将裁切溢出元素
}
3.使用after伪元素清除浮动(推荐使用)
.clearfix:after{/伪元素是行内元素 正常浏览器清除浮动方法/
content: “”;
display: block;
height: 0;
clear:both;
visibility: hidden;
}
.clearfix{
*zoom: 1;/*ie6清除浮动的方式 号只有IE6-IE7执行,其他浏览器不执行/
}
big
small
优点:符合闭合浮动思想,结构语义化正确
缺点:ie6-7不支持伪元素:after,使用zoom:1触发hasLayout.
推荐使用
4.使用before和after双伪元素清除浮动
.clearfix:after,.clearfix:before{ content: “”; display: table; } .clearfix:after{ clear: both; } .clearfix{ *zoom: 1; } big small
优点:代码更简洁
缺点:用zoom:1触发hasLayout.
推荐使用
25、 说说你对栈、队列的理解?应用场景?
1.栈
**栈(stack)**又名堆栈,它是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表。
表尾这一端被称为栈顶,相反地另一端被称为栈底,向栈顶插入元素被称为进栈、入栈、压栈,从栈顶删除元素又称作出栈
所以其按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据,具有记忆作用
实现一个栈:
class Stack { constructor() { this.items = []; } /** * 添加一个(或几个)新元素到栈顶 * @param {*} element 新元素 */ push(element) { this.items.push(element) } /** * 移除栈顶的元素,同时返回被移除的元素 */ pop() { return this.items.pop() } /** * 返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它) */ peek() { return this.items[this.items.length - 1] } /** * 如果栈里没有任何元素就返回true,否则返回false */ isEmpty() { return this.items.length === 0 } /** * 移除栈里的所有元素 */ clear() { this.items = [] } /** * 返回栈里的元素个数。这个方法和数组的length属性很类似 */ size() { return this.items.length } }
关于栈的操作主要的方法如下:
- push:入栈操作
- pop:出栈操作
二.队列
跟栈十分相似,队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
进行插入操作的端称为队尾,进行删除操作的端称为队头,当队列中没有元素时,称为空队列在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出
简单实现一个队列,如下:
class Queue { constructor() { this.list = [] this.frontIndex = 0 this.tailIndex = 0 } enqueue(item) { this.list[this.tailIndex++] = item } unqueue() { const item = this.list[this.frontIndex] this.frontIndex++ return item } }
三.应用场景
栈
借助栈的先进后出的特性,可以简单实现一个逆序输出的功能,首先把所有元素依次入栈,然后把所有元素出栈并输出
包括编译器的在对输入的语法进行分析的时候,例如"()“、”{}“、”[]"这些成对出现的符号,借助栈的特性,凡是遇到括号的前半部分,即把这个元素入栈,凡是遇到括号的后半部分就比对栈顶元素是否该元素相匹配,如果匹配,则前半部分出栈,否则就是匹配出错包括函数调用和递归的时候,每调用一个函数,底层都会进行入栈操作,出栈则返回函数的返回值
生活中的例子,可以把乒乓球盒比喻成一个堆栈,球一个一个放进去(入栈),最先放进去的要等其后面的全部拿出来后才能出来(出栈),这种就是典型的先进后出模型
队列
当我们需要按照一定的顺序来处理数据,而该数据的数据量在不断地变化的时候,则需要队列来帮助解题
队列的使用广泛应用在广度优先搜索中,例如层次遍历一个二叉树的节点值生活中的例子,排队买票,排在队头的永远先处理,后面的必须等到前面的全部处理完毕再进行处理,这也是典型的先进先出模型
参考文献
https://baike.baidu.com/item/%E6%A0%88/12808149
[https://baike.baidu.com/item/%E9%98%9F%E5%88%97/14580481](
26、 说说你对git rebase 和git merge的理解?区别?
git merge和git rebase的区别, 切记:永远用rebase
来谈一下git merge和git rebase的区别。
Git无疑现在已经成为最流行的代码管理工具之一。其中有两个命令,对很多程序员造成了很多的困惑,一个是merge,一个是rebase。
这些困惑主要纠结于到底应该用merge还是用rebase。
在继续深入探讨之前,我先抛出我的观点。如果你想拥有一套稳定的,健壮的代码, 永远要使用rebase。
不为别的,就为了rebase可以给你提供一套清晰的代码历史。
相反的, merge会给你一套乱七八糟的代码历史。当你看到这样的代码历史的时候,我相信你绝对没有心情去研究每一个历史对应的代码。
好,接下来我们就详细分析一下这两个命令的作用。假设我们的repo有这么个主branch: master。
每个程序员在创建自己的代码之前,要首先创建自己的个人分支,然后代码修改开始。
假如你有6个程序员一起工作, 你就会有6个程序员的分支, 如果你使用merge, 你的代码历史树就会有六个branch跟这个主的branch交织在一起。
那个画风我相信对你一定很熟悉。想着那个画风感觉到一切都好无助, 有个词儿比较合适,叫做欲仙欲死。
这就是merge命令下生成的代码分支历史。
那么rebase又能做到什么程度呢?Rebase永远不会导致多个历史分支进行交织。它永远都是一条线。纯洁而又干脆。轻轻爽爽的, 从不拖泥带水。
那为什么会这样呢?
先说一下merge。Merge命令会保留所有commit的历史时间。每个人对代码的提交是各式各样的。尽管这些时间对于程序本身并没有任何意义。但是merge的命令初衷就是为了保留这些时间不被修改。这样也就形成了以merge时间为基准的网状历史结构。每个分支上都会继续保留各自的代码记录, 主分支上只保留merge的历史记录。子分支随时都有可能被删除。子分子删除以后,你能够看到的记录也就是,merge某branch到某branch上了。这个历史记录描述基本上是没有意义的。
还有一个比较有意思的是你不能,也不应该去修改这个历史记录描述。那是因为这个merge记录里面,不仅仅包含你自己的代码,也包含别人的代码。到这里你能想象有多乱吧?
再来说一下rebase, 这个命令会始终把你最新的修改放到最前头。比如你对主branch进行rebase以后, 你的所有修改就会在主branch当前所有的修改之前。你会更有信心保证你的代码运行畅通无阻。通过你自己的测试以后, 你就可以放心的把代码合并到主的branch里面了。
这里值得一提的是,rebase通常是发生在自己的个人branch上的。它的基础就是现有的主branch。这样做的好处就是保证每个人的代码都可以运行在当前最新的主branch的代码上。
这里再提一个比较有意思的现象。在我工作的这么多公司之中,只有不多的几家在使用rebase, 有相当数量的公司还在使用merge。经过观察我发现, 凡是代码管理混乱的项目, 或者整个项目组的做决定者不太清楚代码整洁的重要性, 或者脑子有问题的, 他们都在使用merge。哈哈,我开玩笑呢。
不过, 我还是建议大家去亲身体验一下rebase的好处吧。
27、 说说git常用的命令有哪些?
git链接: 查看git常用命令
28、CDN的特点及意义?
CDN简介:
CDN的全称是Content Delivery Network,即内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络"边缘",使用户可以就近取得所需的内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因所造成的用户访问网站响应速度慢的问题。 (也就是一个服务器的内容,平均分部到多个服务器上,服务器智能识别,让用户获取离用户最近的服务器,提高速度。
实现思路:
其基本思路就是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。
CDN的作用:
实际上,内容分发布网络(CDN)是一种新型的网络构建方式,它是为能在传统的IP网发布宽带丰富媒体而特别优化的网络覆盖层;而从广义的角度,CDN代表了一种基于质量与秩序的网络服务模式。
CDN的特点:
与目前现有的内容发布模式相比较,CDN强调了网络在内容发布中的重要性。通过引入主动的内容管理层的和全局负载均衡,CDN从根本上区别于传统的内容发布模式。
1、CDN网站加速 提高了企业站点(尤其含有大量图片和静态页面站点)的访问速度,并大大提高以上性质站点的稳定性
2、镜像服务 消除了不同运营商之间互联的瓶颈造成的影响,实现了跨运营商的网络加速,保证不同网络中的用户都能得到良好的访问质量。
3、远程加速 远程访问用户根据DNS负载均衡技术 智能自动选择Cache服务器,选择的Cache服务器,加快远程访问的速度
4、带宽优化 自动生成服务器的远程Mirror(镜像)cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的带宽、分担网络流量、减轻原站点WEB服务器负载等功能。
5、集群抗攻击 广泛分布的CDN节点加上节点之间的智能冗于机制,可以有效地预防黑客入侵以及降低各种D.D.o.S攻击对网站的影响,同时保证较好的服务质量。
CDN原理
表现为一个透明的数据传输通道,这种透明性表现在网络的质量保证仅仅停留在数据包的层面,而不能根据内容对象的不同区分服务质量。此外,由于IP网的"尽力而为"的特性使得其质量保证是依靠在用户和应用服务器之间端到端地提供充分的、远大于实际所需的带宽通量来实现的。在这样的内容发布模式下,不仅大量宝贵的骨干带宽被占用,同时ICP的应用服务器的负载也变得非常重,而且不可预计。当发生一些热点事件和出现浪涌流量时,会产生局部热点效应,从而使应用服务器过载退出服务。这种基于中心的应用服务器的内容发布模式的另外一个缺陷在于个性化服务的缺失和对宽带服务价值链的扭曲,内容提供商承担了他们不该干也干不好的内容发布服务。
纵观整个宽带服务的价值链,内容提供商和用户位于整个价值链的两端,中间依靠网络服务提供商将其串接起来。随着互联网工业的成熟和商业模式的变革,在这条价值链上的角色越来越多也越来越细分。比如内容/应用的运营商、托管服务提供商、骨干网络服务提供商、接入服务提供商等等。在这一条价值链上的每一个角色都要分工合作、各司其职才能为客户提供良好的服务,从而带来多赢的局面。从内容与网络的结合模式上看,内容的发布已经走过了ICP的内容(应用)服务器和IDC这两个阶段。IDC的热潮也催生了托管服务提供商这一角色。但是,IDC并不能解决内容的有效发布问题。内容位于网络的中心并不能解决骨干带宽的占用和建立IP网络上的流量秩序。因此将内容推到网络的边缘,为用户提供就近性的边缘服务,从而保证服务的质量和整个网络上的访问秩序就成了一种显而易见的选择。而这就是内容发布网(CDN)服务模式。CDN的建立解决了困扰内容运营商的内容"集中与分散"的两难选择,无疑对于构建良好的互联网价值链是有价值的,也是不可或缺的最优网站加速服务。
29、从浏览器地址栏输入url到显示页面的步骤
基础版本
服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图像等);
浏览器对加载到的资源(HTML、JS、CSS 等)进行语法解析,建立相对应的内部数据结构(如 HTML 的 DOM);
载入解析到的资源文件,渲染页面,完成。
详细版
1.在浏览器地址栏输入URL
2.浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
如果资源未缓存,发起新请求
如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
检验新鲜通常有两个HTTP头进行控制 Expires和Cache-Control:
HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
HTTP1.1增加了Cache-Control:max-age=,值为以秒为单位的最大新鲜时间
浏览器解析URL获取协议,主机,端口,path
4.浏览器组装一个HTTP(GET)请求报文
5.浏览器获取主机ip地址,过程如下:
浏览器缓存
本机缓存
hosts文件
路由器缓存
ISP DNS缓存
DNS递归查询(可能存在负载均衡导致每次IP不一样)
6.打开一个socket与目标IP地址,端口建立TCP链接,三次握手如下:
客服端发送一个TCP的SYN=1,Seq=X的包到服务器端口
服务器发回SYN=1,ACK=X+1,Seq=Y的响应包
客户端发送ACK=Y+1,Seq=Z
7.TCP链接建立后发送HTTP请求
8.服务器接受请求并解析,将请求转发到服务器程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
9.服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
10.处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
11.服务器将响应报文通过TCP连接发送回浏览器
12.浏览器接受HTTP响应,然后根据情况选择关闭TCP连接或者保留重用,关闭TCP连接的四次握手如下
主动方发送Fin=1,Ack=Z,Seq=X报文
被动方发送ACK=X+1,Seq=Z报文
被动方发送Fin=1,ACK=X,Seq=Y报文
主动方发送ACK=Y,Seq=X报文
13.浏览器检查响应状态码:是否为1XX,3XX,4XX,5XX,这些情况处理与2XX不同
14.如何资源可缓存,进行缓存
15.对响应进行解码(例如gzip压缩 )
16.根据资源类型决定如何处理(假设资源为HTML文档)
17.解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释
18.构建DOM树:
Tokenizing:根据HTML规范将字符流解析为标记
Lexing:词法分析将标记转换为对象并定义属性和规则
DOM construction:根据HTML标记关系将对象组成DOM树
19.解析过程中遇到图片、样式表、js文件,启动下载
20.构建CSSOM树:
Tokenizing:字符流转换为标记流
Node:根据标记创建节点
CSSOM:节点创建CSSOM树
21.根据DOM树和CSSOM树构建渲染树:
从DOM树的根节点遍历所有可见节点,不可见节点包括:(script、meta 这样本身不可见的标签,被css隐藏的节点,如 display:none)
对每一个可见节点,找到恰当的CSSOM规则并应用
发不可视节点,找到恰当的CSSOM规则并应用
22.js解析如下:
浏览器创建Document对象并解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystate为loading
HTML解析器遇到没有async和defer的script时,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用document.write()把文本插入到输入流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的文档内容
当解析器遇到设置了 async 属性的 script 时,开始下载脚本并继续解析文档。脚本会在它下载完成后尽快执行,但是解析器不会停下了等它下载。异步脚本禁止使用document.write(),它们可以访问自己script和之前的文档元素
当文档完成解析,document.readState变成interactive
所有defer脚本会按照在文档出现的顺序执行,延迟脚本能访问完整文档树,禁止使用document.write()
浏览器**在Document对象上触发DOMContentLoaded事件
此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些内容完成载入并且所有异步脚本完成载入和执行,document.readState变为complete,window触发load事件
23.显示页面(HTML解析过程中会逐步显示页面)
详细简版
1.从浏览器接收 url 到开启网络请求线程(这一部分可以展开浏览器的机制以及进程与线程之间的关系)
2.开启网络线程到发出一个完整的HTTP请求(这一部分涉及到dns查询,TCP/IP 请求,五层原因特网协议栈等知识)
3.从服务器接收到请求到对应后台接收到请求(这一部分可能涉及到负载均衡,安全拦截以及后台内部的处理等等)
4.后台和前台的 HTTP 交互(这一部分包括 HTTP 头部、响应码、报文结构、cookie 等知识,可以提下静态资源的 cookie 优化,以及编码解码,如gzip压缩等)
5.单独拎出来的缓存问题,HTTP 的缓存(这部分包括http缓存头部,ETag,catch-control 等)
6.浏览器接受到 HTTP 数据包后的解析流程(解析html -词法分析然后解析成 dom 树、解析 css 生存 css 规则树、合并成 render 树,然后 layout、painting渲染、复合图层的合成、GPU 绘制、外链资源的处理、loaded 和 DOMContentLoaded 等)
7.CSS的可视化格式模型(元素的渲染规则,如包含块,控制框,BFC,IFC等概念)
8.JS引擎解析过程(JS的解释阶段,预处理阶段,执行阶段生存执行上下文,V0,作用域链、回收机制等等)
9.其它(可以拓展不同的知识模块,如跨域,web安全,hybrid模式等等内容)
30、 如果需要手动写动画,你认为最小时间间隔是多久,为什么?
写动画从来没怎么注意过,今天看了个问题,说css3写动画最小的时间间隔是多少,其原因,之前一直想着只要在人眼识别的范围内都可以把。
现在记录一下,涨涨姿势。
多数显示器的默认频率是60HZ,即每秒刷新60次。所以理论上的最小间隔是 1/60*1000ms = 16.7ms
31、 SPA(单页应用)首屏加载速度慢怎么解决?
(1)减小入口文件积
(2)静态资源本地缓存
(3)UI框架按需加载
(4)图片资源的压缩
(5)组件重复打包
(6)开启GZip压缩
(7)使用SSR