-
SYN(synchronous建立联机)
-
ACK(acknowledgement 确认)
-
PSH(push传送)
-
FIN(finish结束)
-
RST(reset重置)
-
URG(urgent紧急)
第一次握手:主机A发送位码为SYN=1
,随机产生Seq number=1234567
的数据包到服务器,主机B由SYN=1
知道,A要求建立联机;(第一次握手,由浏览器发起,告诉服务器我要发送请求了)
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1)
,SUN=1,ACK=1234567 + 1
,随机产生Seq=7654321
的包;(第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶紧发送吧)
第三次握手:主机A收到后检查ack number
是否正确,即第一次发送的seq number+1
,以及位码SYN
是否为1,若正确,主机A会再发送ack number=(主机B的seq+1)
,ack=7654321 + 1
,主机B收到后确认Seq
值与ACK=7654321+ 1
则连接建立成功;(第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧)
总是要问:为什么需要三次握手,两次不行吗?其实这是由TCP的自身特点可靠传输决定的。客户端和服务端要进行可靠传输,那么就需要确认双方的
接收
和发送
能力。第一次握手可以确认客服端的发送能力
,第二次握手,服务端SYN=1,Seq=Y
就确认了发送能力
,ACK=X+1
就确认了接收能力
,所以第三次握手才可以确认客户端的接收能力
。不然容易出现丢包的现象。
第三次握手的必要性?
试想如果是用两次握手,则会出现下面这种情况:如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。
数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。
什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
这里在补充一点关于SYN-ACK 重传次数的问题:服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
ISN是固定的吗?
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据。
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
SYN攻击?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。
SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。
netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
-
缩短超时(SYN Timeout)时间
-
增加最大半连接数
-
过滤网关防护
-
SYN cookies技术
第三部分 HTTP请求
HTTP 发展历史
HTTP/0.9
-
只有一个命令GET
-
响应类型: 仅 超文本
-
没有header等描述数据的信息
-
服务器发送完毕,就关闭TCP连接
HTTP/1.0
-
增加了很多命令(post HESD )
-
增加
status code
和header
-
多字符集支持、多部分发送、权限、缓存等
-
响应:不再只限于超文本 (Content-Type 头部提供了传输 HTML 之外文件的能力 — 如脚本、样式或媒体文件)
HTTP/1.1
-
持久连接。TCP三次握手会在任何连接被建立之前发生一次。最终,当发送了所有数据之后,服务器发送一个消息,表示不会再有更多数据向客户端发送了;则客户端才会关闭连接(断开 TCP)
-
支持的方法:
GET
,HEAD
,POST
,PUT
,DELETE
,TRACE
,OPTIONS
-
进行了重大的性能优化和特性增强,分块传输、压缩/解压、内容缓存磋商、虚拟主机(有单个IP地址的主机具有多个域名)、更快的响应,以及通过增加缓存节省了更多的带宽
HTTP2
-
所有数据以二进制传输。HTTP1.x是基于文本的,无法保证健壮性,HTTP2.0绝对使用新的二进制格式,方便且健壮
-
同一个连接里面发送多个请求不再需要按照顺序来
-
头信息压缩以及推送等提高效率的功能
HTTP3
- QUIC“快速UDP互联网连接”(Quick UDP Internet Connections)
HTTP3 的主要改进在传输层上。传输层不会再有我前面提到的那些繁重的 TCP 连接了。现在,一切都会走 UDP。
HTTP3详细介绍[2]
HTTP协议特点
-
支持客户/服务器模式。
-
简单快速客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有 GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于 HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
-
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。
-
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
-
无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
现在 HTTP3 最快!
HTTP报文
请求报文:
响应报文:
各协议与HTTP协议关系
-
DNS 服务:解析域名至对应的IP地址
-
HTTP 协议:生成针对目标Web服务器的HTTP请求报文
-
TCP 协议:将请求报文按序号分割成多个报文段
-
IP 协议:搜索对方的地址,一边中转一边传送
-
TCP 协议:按序号以原来的顺序重组请求报文请求的处理结果也同样利用TCP/IP协议向用户进行回传
- TCP是底层通讯协议,定义的是数据传输和连接方式的规范;
-
HTTP是应用层协议,定义的是传输数据的内容的规范;
-
HTTP协议中的数据是利用TCP协议传输的,所以支持HTTP也就一定支持TCP。
关于HTTP的东西还有很多,我在最后放了张大图[3]。
HTTPS
在HTTP的基础上再加一层TLS(传输层安全性协议)或者SSL(安全套接层),就构成了HTTPS协议。
HTTPS 默认工作在 TCP 协议443端口,它的工作流程一般如以下方式:
-
TCP 三次同步握手
-
客户端验证服务器数字证书
-
DH 算法协商对称加密算法的密钥、hash 算法的密钥
-
SSL 安全加密隧道协商完成
-
网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改。
-
客户端向服务端发送
Client Hello
消息,其中携带客户端支持的协议版本、加密算法、压缩算法以及客户端生成的随机数; -
服务端收到客户端支持的协议版本、加密算法等信息后;
-
向客户端发送
Server Hello
消息,并携带选择特定的协议版本、加密方法、会话 ID 以及服务端生成的随机数; -
向客户端发送
Certificate
消息,即服务端的证书链,其中包含证书支持的域名、发行方和有效期等信息; -
向客户端发送
Server Key Exchange
消息,传递公钥以及签名等信息; -
向客户端发送可选的消息
Certificate Request
,验证客户端的证书; -
向客户端发送
Server Hello Done
消息,通知服务端已经发送了全部的相关信息; -
客户端收到服务端的协议版本、加密方法、会话 ID 以及证书等信息后,验证服务端的证书;
-
向服务端发送
Client Key Exchange
消息,包含使用服务端公钥加密后的随机字符串,即预主密钥(Pre Master Secret
); -
向服务端发送
Change Cipher Spec
消息,通知服务端后面的数据段会加密传输; -
向服务端发送
Finished
消息,其中包含加密后的握手信息; -
服务端收到
Change Cipher Spec
和Finished
消息后; -
向客户端发送
Change Cipher Spec
消息,通知客户端后面的数据段会加密传输; -
向客户端发送
Finished
消息,验证客户端的Finished
消息并完成 TLS 握手;
TLS 握手的关键在于利用通信双发生成的随机字符串和服务端的证书公钥生成一个双方经过协商后的对称密钥,这样通信双方就可以使用这个对称密钥在后续的数据传输中加密消息数据,防止中间人的监听和攻击,保证通讯安全。
HTTPS连接 需要7次握手,3次TCP + 4次TLS。
第四部分 服务器处理请求并返回 HTTP 报文
每台服务器上都会安装处理请求的应用——Web Server。常见的Web Server 产品有 apache
、nginx
、IIS
或 Lighttpd
等。
HTTP请求一般可以分为两类,静态资源 和 动态资源。
请求访问静态资源,这个就直接根据url地址去服务器里找就好了。
请求动态资源的话,就需要web server把不同请求,委托给服务器上处理相应请求的程序进行处理(例如 CGI 脚本,JSP 脚本,servlets,ASP 脚本,服务器端 JavaScript,或者一些其它的服务器端技术等),然后返回后台程序处理产生的结果作为响应,发送到客户端。
服务器在处理请求的时候主要有三种方式:
-
第一种:是用一个线程来处理所有的请求,并且同时只能处理一个请求,但是这样的话性能是非常的低的。
-
第二种:是每一个请求都给他分配一个线程但是当链接和请求比较多的时候就会导致服务器的cpu不堪重负。
-
第三种:就是采用复用I/O的方式来处理例如通过epoll方式监视所有链接当链接状态发生改变的时候才去分配空间进行处理。
第五部分 浏览器渲染页面
DOM树
字节 → 字符 → 令牌 → 节点 → 对象模型。
Hello web performance students!
![](awesome-photo.jpg)
-
转换: 浏览器从磁盘或网络读取 HTML 的原始字节,并根据文件的指定编码(例如 UTF-8)将它们转换成各个字符。
-
令牌化: 浏览器将字符串转换成 W3C HTML5 标准规定的各种令牌,例如,“”、“”,以及其他尖括号内的字符串。每个令牌都具有特殊含义和一组规则。
-
词法分析: 发出的令牌转换成定义其属性和规则的“对象”。
-
DOM 构建: 最后,由于 HTML 标记定义不同标记之间的关系(一些标记包含在其他标记内),创建的对象链接在一个树数据结构内,此结构也会捕获原始标记中定义的父项-子项关系: HTML 对象是 body 对象的父项,body 是 paragraph 对象的父项,依此类推。
CSS 对象模型 (CSSOM)
body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }
布局树Layout Tree
-
DOM 树与 CSSOM 树合并后形成渲染树。
-
渲染树只包含渲染网页所需的节点。
-
布局计算每个对象的精确位置和大小。
-
最后一步是绘制,使用最终渲染树将像素渲染到屏幕上。
渲染
渲染流程:
-
获取DOM后分割为多个图层
-
对每个图层的节点计算样式结果 (Recalculate style–样式重计算)
-
为每个节点生成图形和位置 (Layout–重排,回流)
-
将每个节点绘制填充到图层位图中 (Paint–重绘)
-
图层作为纹理上传至GPU
-
组合多个图层到页面上生成最终屏幕图像 (Composite Layers–图层重组)
创建图层
div {width: 100px;height: 100px;}
.position_ {background: pink;position: fixed;z-index: 20;}
.box_3d {background: red;transform: translate3d(100px,30px,10px);}
.will-change {background: #f12312;will-change: transform;}
.transform {background: #302912;transform: skew(30deg, 20deg);}
在 chrome 上查看 Layers.
如果没有打开Layers,按下图打开:
知道图层的存在,我们可以手动打开一个图层,通过添加
transform: translateZ(0)
这样回流和重绘的代价就小了,效率就会大大提高。但是不要滥用这个属性,否则会大大增加内存消耗。—— 开启GPU加速。
回流和重绘
- 重绘
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
- 回流
当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
回流必将引起重绘,而重绘不一定会引起回流。
引起回流:
-
页面首次渲染
-
浏览器窗口大小发生改变
-
元素尺寸或位置发生改变
-
元素内容变化(文字数量或图片大小等等)
-
元素字体大小变化
-
添加或者删除可见的DOM元素
-
激活CSS伪类(例如::hover)
-
查询某些属性或调用某些方法
引起回流的属性和方法:
-
clientWidth、clientHeight、clientTop、clientLeft
-
offsetWidth、offsetHeight、offsetTop、offsetLeft
-
scrollWidth、scrollHeight、scrollTop、scrollLeft
-
scrollIntoView()、scrollIntoViewIffNeeded()
-
getComputedStyle()
-
getBoundingClientRect()
-
scrollTo()
如何减少回流
- css
-
避免使用table布局;
-
尽可能在DOM树的最末端改变class;
-
避免设置多层内联样式;
-
将动画效果应用到position属性为absolute或fixed的元素上;
-
避免使用CSS表达式(例如:calc())。
- JS
-
避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
-
避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
-
也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
-
避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
-
对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
第六部分 断开连接:TCP 四次分手
-
刚开始双方都处于established状态,假如是客户端先发起关闭请求
-
第一次挥手:客户端发送一个FIN报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态
-
第二次挥手:服务端收到FIN之后,会发送ACK报文,且把客户端的序列号值+1作为ACK报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT状态
-
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送FIN报文,且指定一个序列号。此时服务端处于LAST_ACK的状态
-
需要过一阵子以确保服务端收到自己的ACK报文之后才会进入CLOSED状态,服务端收到ACK报文之后,就处于关闭连接了,处于CLOSED状态。
挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。
只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
为什么客户端发送ACK之后不直接关闭,而是要等一阵子才关闭?
客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
如果不等待,客户端直接跑路,当服务端还有很多数据包要给客户端发,且还在路上的时候,若客户端的端口此时刚好被新的应用占用,那么就接收到了无用数据包,造成数据包混乱。
为什么TIME_WAIT状态需要经过2MSL(最大报文生存时间)才能返回到CLOSE状态?
理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端;1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达。
关于HTTP
高清图片上传不了,已传百度云,大家可以直接下载:
链接: https://pan.baidu.com/s/1OwiWpRWVrj1gQ1z9a3vjqg?pwd=dyka
提取码: dyka
参考资料
[1]
你所不知道的 HSTS:https://www.barretlee.com/blog/2015/10/22/hsts-intro/
[2]
HTTP3详细介绍:https://http3-explained.haxx.se/zh/zh
[3]
大图: #关于http
作者:FinGet
https://juejin.cn/post/6935232082482298911
- 完 -
推荐阅读
Chrome 又搞事情,document.domain跨域直接废了
每日前端干货,关注前端开发博客!
基础学习:
前端最基础的就是 HTML , CSS 和 JavaScript 。
网页设计:HTML和CSS基础知识的学习
HTML是网页内容的载体。内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字、图片、视频等。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
CSS样式是表现。就像网页的外衣。比如,标题字体、颜色变化,或为标题加入背景图片、边框等。所有这些用来改变内容外观的东西称之为表现。
动态交互:JavaScript基础的学习
JavaScript是用来实现网页上的特效效果。如:鼠标滑过弹出下拉菜单。或鼠标滑过表格的背景颜色改变。还有焦点新闻(新闻图片)的轮换。可以这么理解,有动画的,有交互的一般都是用JavaScript来实现的。
[2]
HTTP3详细介绍:https://http3-explained.haxx.se/zh/zh
[3]
大图: #关于http
作者:FinGet
https://juejin.cn/post/6935232082482298911
- 完 -
推荐阅读
Chrome 又搞事情,document.domain跨域直接废了
每日前端干货,关注前端开发博客!
基础学习:
前端最基础的就是 HTML , CSS 和 JavaScript 。
网页设计:HTML和CSS基础知识的学习
HTML是网页内容的载体。内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字、图片、视频等。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
[外链图片转存中…(img-WI3lbBa5-1714766192058)]
CSS样式是表现。就像网页的外衣。比如,标题字体、颜色变化,或为标题加入背景图片、边框等。所有这些用来改变内容外观的东西称之为表现。
[外链图片转存中…(img-yTAzE5kn-1714766192059)]
动态交互:JavaScript基础的学习
JavaScript是用来实现网页上的特效效果。如:鼠标滑过弹出下拉菜单。或鼠标滑过表格的背景颜色改变。还有焦点新闻(新闻图片)的轮换。可以这么理解,有动画的,有交互的一般都是用JavaScript来实现的。