网络接口层(物理层、数据链路层)->网络层->运输层->应用层
应用层(会话层、表示层、应用层):文件传输、访问和管理
运输层:运输层的主要功能是提供端到端(进程-进程)的可靠通信(TCP,UDP)
网络层:功能是把分组发往目标网络或主机。
网络接口层(物理层、数据链路层):封装成帧,透明传输
●连接方面,http1.0默认使用非持久连接,而http1.1默认使用持久连接(keep-alive)。http1.1 通过使用持久连接来使多个http请求复用同- -个TCP连接,以此来避免使用非持久连接时每次需要建立连接的时延。
●资源请求方面,在http1.0中,存在-些浪费带宽的现象,例如客户端只是需要某个对象的-部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206 (Partial Content) ,这样就方便了开发者自由的选择以便于充分利用带宽和连接。
●缓存方面,在http1.0中主要使用header里的If-Modified-Since. Expires来做为缓存判断的标准,http1.1则引入了更多的缓存控制策略,例如Etag、lf-Unmodified-Since. If-Match、 If-None-Match 等更多可供选择的缓存头来控制缓存策略。
●http1.1 中新增了host字段,用来指定服务器的域名。http1.0 中认为每台服务器都绑定一个唯- -的 IP地址,因此,请求消息中的URL并没有传递主机名(hostname) 。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享-个IP地址。 因此有了host字段,这样就可以将请求发往到同一台服务器上的不同网站。
●http1.1 相对于http1.0还新增了很多请求方法,如PUT、HEAD、OPTIONS等。
●二进制协议: HTTP2 是一个二进制协议。在HTTP/1.1版中,报文的头信息必须是文本(ASCII 编码) ,数据体可以是文本,也可以是二进制。HTTP/2 则是-个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧" ,可以分为头信息帧和数据帧。帧的概念是它实现多路复用的基础。
●多路复用: HTTP/2实现了多路复用,HTTP/2仍然复用TCP连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了队头堵塞的问题。
●数据流: HTTP/2使用了数据流的概念,因为HTTP/2的数据包是不按顺序发送的,同-一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为-一个数据流。每个数据流都有一个独一无的编号。数据包发送时,都必须标记数据流ID,用来区分它属于哪个数据流。
●头信息压缩: HTTP/2 实现了头信息压缩,由于HTTP 1.1协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent, - -模-样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这- -点做了优化,引入了头信息压缩机制。- -方面,头信息使用gzip或compress压缩后再发送;另-方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
●服务器推送: HTTP/2允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少-些延迟时间。这里需要注意的是http2下服务器主动推送的是静态资源,和WebSocket以及使用SSE等方式向客户端发送即时数据的推送是不同的。
在需要发送 HTTP 请求时,考虑如何减少请求次数;
1.使用缓存
2.合并请求
http2的问题:
HTTP/2 多个 Stream 请求都是在一条 TCP 连接上传输,这意味着多个 Stream 共用同一个 TCP 滑动窗口,所以一旦发生丢包现象,就会触发TCP的重传机制,这样在一个TCP连接中的所有HTTP请求都必须等待这个丢了的包被重传回来,造成阻塞。
HTTP3将HTTP下层的TCP协议换成了UDP来解决丢包问题。UDP是不管请求响应的顺序和丢包,
即使发生丢包,其他的请求也不会阻塞。UDP是不可靠传输的,但是基于UDP的QUIC协议可以实现类似TCP的可靠传输
QUIC为什么不会发生队头阻塞?
QUIC 也借鉴 HTTP/2 里的 Stream 的概念,在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (Stream)。
但是 QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口。
假如 Stream2 丢了一个 UDP 包,也只会影响 Stream2 的处理,不会影响其他 Stream,与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。
所以,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响。
HTTP3采用UDP作为传输层协议,重新实现了无序连接,并在此基础上通过有序的QUIC Stream提供了多路复用
区别:
Http和https使用完全不同的连接方法和不同的端口。前者是80,后者是443。
Http连接是非常简单和无状态的;HttpS协议是由SSL/TLS+HTTP协议构建的网络协议,可用于加密传输和身份认证。它比HTTP协议更安全。
过程:
HTTP先和SSL通信,再由SSL和TCP通信,相当于SSL被嵌在了HTTP和TCP之间。
在通信建立前采用非对称加密的方式交换会话秘钥,后续不再使用非对称加密。在
通信过程中全部使用对称加密的会话秘钥的方式加密明文数据。
tsl四次握手
第一次握手:
客户端向服务器发送Client Hello消息,消息以明文的形式传输,里面包括客户端支持的协议版本、加密套件、压缩算法、客户端生成的一个随机数R1、扩展字段等。(交换版本,随机数R1)
第二次握手:
应对客户端发来的Client Hello,服务器将发送Server Hello消息进行响应,该消息以明文的形式传输,相应消息包括确认使用的协议版本、由服务器生成的随机数R2,确认使用的加密套件、确认使用的压缩方法,服务端生成把证书、随机数R2、会话密钥生成算法,一同发给客户端;(响应第一次握手,确认版本,随机数R2,会话密钥生成算法,发送数字证书)
在客户端收到Server Hello Done之后并没有马上进行第三次握手,而是先对服务器传来的证书进行验证
在这个过程中若出现了验证不通过的结果,则抛出相应的错误;若验证通过,就再生成一个随机数R3,并用服务器公钥进行加密后发送给服务端,利用三个随机数和算法生成一个会话密钥。
第三次握手:
就是客户端将加密过后的随机数R3发送给服务器,服务器则会用自己的私钥解密得出随机数R3。到这里客户端和服务器都拥有了三个随机数R1、R2和R3,再用相同的算法和这三个随机数生成一个同样的会话密钥,用于握手结束后传输数据的对称加密。(生成对称密钥)
第四次握手:
服务器向客户端通知,后面发送的消息都会使用协商出来的对称密钥进行加密。
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 是单向认证,客户端只会验证了服务端的身份,但是服务端并不会验证客户端的身份。
(1)解析URL:首先会对URL进行解析,分析所需要使用的传输协议和请求的资源的路径。如果输入的URL中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查URL中是否出现了非法字符,如果存在非法字符,则对非法字符进行转义后再进行下一-过程。
(2)缓存判断:浏览器会判断所请求的资源是否在缓存里, 如果请求的资源在缓存里并且没有失效,那么就直接使用,否则向服务器发起新的请求。
(3) DNS解析:下一 步首先需要获取的是输入的URL中的域名的IP地址,首先会判断本地是否有该域名的IP地址的缓存,如果有则使用,如果没有则向本地DNS服务器发起请求。本地DNS服务器也会先检查是否存在缓存,如果没有就会先向根域名服务器发起请求,获得负责的顶级域名服务器的地址后,再向顶级域名服务器请求,然后获得负责的权威域名服务器的地址后,再向权威域名服务器发起请求,最终获得域名的IP地址后,本地DNS服务器再将这个IP地址返回给请求的用户。用户向本地DNS服务器发起请求属于递归请求,本地DNS服务器向各级域名服务器发起请求属于迭代请求。
(4)获取MAC地址:当浏览器得到 IP地址后,数据传输还需要知道目的主机MAC地址,因为应用层下发数据给传输层,TCP协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的IP地址作为目的地址。然后将下发给数据链路层,数据链路层的发送需要加入通信双方的MAC地址,本机的MAC地址作为源MAC地址,目的MAC地址需要分情况处理。通过将IP地址与本机的子网掩码相与,可以判断是否与请求主机在同一个子网里,如果在同一个子网里,可以使用APR协议获取到目的主机的MAC地址,如果不在一个子网里, 那么请求应该转发给网关,由它代为转发,此时同样可以通过ARP协议来获取网关的MAC地址,此时目的主机的MAC地址应该为网关的地址。
(5) TCP三次握手:下面是 TCP建立连接的三次握手的过程,,首先客户端向服务器发送一个SYN连接请求报文段和一个随机序号,服务端接收到请求后向服务器端发送一个SYN ACK报文段,确认连接请求,并且也向客户端发送一个随机序号。客户端接收服务器的确认应答后,进入连接建立的状态,同时向服务器也发送一个ACK 确认报文段,服务器端接收到确认后,也进入连接建立状态,此时双方的连接就建立起来了。
(6) HTTPS握手:如果使用的是HTTPS协议,在通信前还存在TLS的一个四次握手的过程。首先由客户端向服务器端发送使用的协议的版本号、-个随机数和可以使用的加密方法。服务器端收到后,确认加密的方法,也向客户端发送一个随机数和自己的数字证书。客户端收到后,首先检查数字证书是否有效,如果有效,则再生成-个随机数,并使用证书中的公钥对随机数加密,然后发送给服务器端,并且还会提供一个前面所有内容的hash值供服务器端检验。服务器端接收后,使用自己的私钥对数据解密,同时向客户端发送一个前面所有内容的 hash值供客户端检验。这个时候双方都有了三个随机数,按照之前所约定的加密方法,使用这三个随机数生成一把秘钥, 以后双方通信前,就使用这个秘钥对数据进行加密后再传输。.
(7)返回数据:当页面请求发送到服务器端后, 服务器端会返回-一个html文件作为响应,浏览器接收到响应后,开始对html文件进行解析,开始页面的渲染过程。
(8)页面渲染:浏览器首先会根据html文件构建DOM树,根据解析到的css 文件构建CSSOM树,如果遇到script标签,则判端是否含有defer或者async属性,要不然script的加载和执行会造成页面的渲染的阻塞。当DOM树和CSSOM树建立好后,根据它们来构建渲染树。渲染树构建好后,会根据渲染树来进行布局。布局完成后,最后使用浏览器的UI接口对页面进行绘制。这个时候整个页面就显示出来了。
(9) TCP四次挥手:最后-步是TCP断开连接的四次挥手过程。若客户端认为数据发送完成,则它需要向服务端发送连接释放请求。服务端收到连接释放请求后,会告诉应用层要释放TCP链接。然后会发送ACK包,并进入CLOSE WAIT状态,此时表明客户端到服务端的连接已经释放,不再接收客户端发的数据了。但是因为TCP连接是双向的,所以服务端仍旧可以发送数据给客户端。服务端如果此时还有没发完的数据会继续发送,完毕后会向客户端发送连接释放请求,然后服务端便进入LAST-ACK状态。客户端收到释放请求后,向服务端发送确认应答,此时客户端进入TIME-WAIT状态。该状态会持续2MSL (最大段生存期,指报文段在网络中生存的时间,超时会被抛弃)时间,若该时间段内没有服务端的重发请求的话,就进入CLOSED状态。当服务端收到确认应答后,也便进入CLOSED状态。
1.TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保 证可靠交付
2.TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
3.TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
场景
TCP可靠原因:
1.超时重传机制
2.流量控制(滑动窗口,也就是缓冲区的概念,类似于控制异步并发)
3.确认应答机制
若数据通信完整性需要通信实时性,则选用TCP(传文件、重要状态),因为能保证数据的安全并且也保证了对方能够收到。反之选用UDP(视频、实时通信)。因为视频文件如果丢失一小部分不影响整体效果。
强缓存:
http1.0中是Expires字段 绝对到期时间 不常用
第一次响应设置一个强制缓存到期时间 后续在到期时间之前的请求都从缓存中拿到资源
'Expries': new Date(时间).toUTCString()
问题:
Expires是服务器的绝对时间,所以服务器和客户端时间偏差比较大的时候,就会导致缓存混乱
http1.1是Cache-Control字段
'Cache-Control': 'public,max-age=31536000'
max-age xx秒 滑动到期时间
第一次响应设置一个强制缓存滑动时间 后续滑动时间内的请求都从缓存中拿到资源
强缓存缺点:强制缓存时间内的资源不能更新
协商缓存:
last-modified字段和if-modified-since字段
问题:
1.在没有修改文件内容情况下文件的最后修改时间可能也会改变,这会导致客户端认为这文件被改动了,从而重新请求;
2.时间戳只精确到秒
last-modified字段 响应头上返回最后一次资源更新的时间
if-modified-since字段 下次请求头上会带上此字段
若last-modified字段与if-modified-since字段时间一致,则返回304状态码,表示资源无更新
若last-modified字段与if-modified-since字段时间不一致,则从服务器请求资源,状态码200,并更新last-modified
http1.1新增ETag字段 etag实体标签
响应头部中 Etag:唯一标识响应资源;
请求头部中的 If-None-Match:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。
首先强缓存只有catch-control会生效,进行判断,如果没有那么判断etag再判断last-modified,如果两者都没有变化就返回304,有一个变了就返回200
Accept:浏览器能够处理的内容类型
Accept-Charset:浏览器能够显⽰的字符集
Accept-Encoding:浏览器能够处理的压缩编码
Accept-Language:浏览器当前设置的语⾔
Connection:浏览器与服务器之间连接的类型
Cookie:当前页⾯设置的任何Cookie
Host:发出请求的页⾯所在的域
Referer:发出请求的页⾯的URL
User-Agent:浏览器的⽤户代理字符串
持久连接keep-alive虽然解决了不用多次建立tcp连接,但是并不能缩短数据请求回来的时间,应该每个请求必须是有序的。而http2提出数据流概念,它能标记每个http请求,相当于唯一id,所以请求可以乱序,这样大大提高了传输数据的时间,解决了堆头阻塞。
1.DNS解析
将域名解析成ip地址
2.发送TCP连接
传包 TCP三次握手、四次挥手 2MSL的原因
3.发送http请求
特殊请求报文 keep-alive https http2 先进先出 队头阻塞
4.服务器获取请求并返回http响应报文
特殊响应报文 状态码 浏览器缓存
5.浏览器解析并渲染页面
HTML-DOM CSS-CSSOM 渲染树 减少重溯和回流-重绘和重排 js解析 事件循环
6.断开连接
四次挥手的原因
浏览器缓存-本机host文件-路由器缓存-DNS服务器查询(迭代最好)
递归查询:
本机-1服务器无果-2服务器无果-3服务器无果-…
迭代查询:
本机-1服务器无果拿到2服务器ip
本机-2服务器无果拿到3服务器ip
本机-3服务器无果拿到4服务器ip
…
优点:对服务器的压力小
客户端为和服务器time-wait状态,本次连接丢的包可能会在下次连接时回来,这显然不是我们想要的结果,设置一个MSL时间,该时间内没回来的数据包将会被丢弃,然后再次发送一次请求
为什么不是两次握手?
这主要是为了防止已失效的连接请求报文段突然又传送到了 B,从而造成资源浪费。
考虑一种异常情况,即 A 发出的第一个连接请求报文段并没有丢失,而是在某些网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 B。本来这是一个早已失效的报文段,但 B 收到此失效的连接请求报文段后,就误认为是 A 又发出了一次新的连接请求,于是就向 A 发出确认报文段,同意建立连接。假定不采用报文握手,那么只要 B 发出确认,新的连接就建立了。
由于现在 A 并没有发出建立连接的请求,因此不会理睬 B 的确认,也不会向 B 发送数据,但 B 却认为新的运输连接已经建立了,并一直等待 A 发来数据,B 的许多资源就这样浪费了。
采用三次握手的办法,可以防止上述现象的发生,例如在刚才的异常情况下,A 不会向 B 的确认发出确认,B 由于收不到确认,就知道 A 并没有要求建立连接。
为什么不是3次挥手?
向 B 发送一个连接释放请求报文,代表 A 的数据传送完了,请求释放连接;
B 收到后,B 立即向 A 发送一个确认报文,代表 B 已经知道 A 没有数据要传送了,但是 B 可能还有数据要向 A 传送;
B 的数据传送完后,向 A 发送一个连接释放请求报文,代表 B 的数据也传送完了,请求释放连接;
A 收到后,也立即向 B 发送一个确认报文,同时等待 2MSL 后,连接断开。
options 请求就是预检请求,可用于检测服务器允许的 http 方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 OPTIONS 请求,即 CORS 预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
什么是关键渲染路径?
GUI线程中把htmlcss代码解析到渲染在页面上的这条流水线
过程
进程是CPU分配内存的最小最小单位
线程是CPU调度的最小单位
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
主要的进程有:
GUI渲染线程
● DOM,CSSOM,render树,布局和绘制,重溯和回流
解析DOM时遇到JS会堵塞DOM解析
● 与JS引擎线程互斥
● 当GUI渲染线程队列中有任务时,会在JS引擎空闲的时候再渲染
JS引擎线程(V8)
● 也叫JS内核,处理JS代码
● 与GUI渲染线程互斥
● 当JS引擎线程有任务时,会把GUI线程挂起
● JS执行时间过长会堵塞页面渲染
事件触发线程
● Event Loop的核心线程
● 当执行条件满足或对应的事件触发时,会将对应的触发事件放入队列的尾部等待JS引擎线程处理
定时器触发线程
为什么要有这个线程?
JS是单线程的,如果堵塞会影响定时器的准确性,所以单独有个线程来计时
● 当计时结束后,将对应的回调事件放入事件队列中等待JS引擎执行
异步http请求线程
● 基本同上
css不会阻塞DOM解析,会阻塞dom渲染
DOM树和CSSOM树的解析是互不影响的,因此css不会阻塞页面的解析,会阻塞render树的生成
js会阻塞dom解析,如果没有async和defer标签的话
公钥;
持有者信息;
证书认证机构(CA)的信息;
数字签名及使用的算法;
证书有效期;
额外信息;
首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
最后将 Certificate Signature 添加在文件证书上,形成数字证书;
首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
流量控制和拥塞控制的区别
流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止分组丢失的。
拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况。
拥塞窗口
拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。
拥塞窗口 cwnd 变化的规则:
只要网络中没有出现拥塞,cwnd 就会增大;
但网络中出现了拥塞,cwnd 就减少;
那么怎么知道当前网络是否出现了拥塞呢?
其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。
拥塞控制的本质就是使用算法控制拥塞窗口,从而避免过多的数据注入到网络。
拥塞控制算法
拥塞控制算法:慢启动、拥塞避免、快速重传、快速恢复
在 TCP 连接建立完毕后,会先使用慢启动算法,指数级逐渐增大拥塞窗口(+1 +2 +4 +8…)。
当拥塞窗口达到慢启动门限 ssthresh(slow start threshold)时,会使用拥塞避免算法,线性逐渐增大拥塞窗口。就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。当触发了重传机制,也就进入了「拥塞发生算法」。
当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种:
超时重传
快速重传
当发生了「超时重传」,这个时候,ssthresh 和 cwnd 的值会发生变化:
ssthresh 设为 cwnd/2,
cwnd 重置为 1 (是恢复为 cwnd 初始化值,我这里假定 cwnd 初始化值 1)
接着,就重新开始慢启动,慢启动是会突然减少数据流的。但是这种方式太激进了,反应也很强烈,会造成网络卡顿。
当发生了「快速重传」,这个时候,ssthresh 和 cwnd 的值会发生变化:
cwnd = cwnd/2 ,也就是设置为原来的一半;
ssthresh = cwnd;
进入快速恢复算法
正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了:
然后,进入快速恢复算法如下:
拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);
重传丢失的数据包;
如果再收到重复的 ACK,那么 cwnd 增加 1;
如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态
DNS在进行区域传输的时候使用TCP协议,域名解析时则使用UDP协议
一:客户端想要释放连接,向服务端发送一段TCP报文
二:服务器端接受到从客户端发出的TCP报文后,得知客户端想要释放连接,随后服务端结束
ESTABLISHED阶段,进入CLOST-WAIT阶段(半关闭状态)并返回一段TCP报文
三:服务器端自从发出ACK确认报文后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端
方向上的连接准备,再次向客户端发出一段TCP报文。
四:客户端收到从服务器发出的TCP报文,确认了服务器端已经做好释放连接的准备,结束FINWAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文
随后客户端开始在TIME-WAIT阶段等待2MSL。
为什么客户端在TIME-WAIT阶段要等待2MSL?
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。
如果服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文。
2=1(没有收到请求的时间)+1(服务端重新发送第三次请求传输的时间)
1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
「200 OK」是最常见的成功状态码,表示一切正常。
「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
3xx 类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。
4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。
先说明下安全和幂等的概念:
在 HTTP 协议里,所谓的「安全」是指请求方法不会「破坏」服务器上的资源。
所谓的「幂等」,意思是多次执行相同的操作,结果都是「相同」的。
GET 方法就是安全且幂等的,因为它是「只读」操作,无论操作多少次,服务器上的数据都是安全的,且每次的结果都是相同的。所以,可以对 GET 请求的数据做缓存,这个缓存可以做到浏览器本身上(彻底避免浏览器发请求)
POST 因为是「新增或提交数据」的操作,会修改服务器上的资源,所以是不安全的,且多次提交数据就会创建多个资源,所以不是幂等的
RPC本质上不算是协议,而是一种调用方式,而像gRPC和thrift这样的具体实现,才是协议,它们是实现了RPC调用的协议。目的是希望程序员能像调用本地方法那样去调用远端的服务方法。同时RPC有很多种实现方式,不一定非得基于TCP协议。
从发展历史来说,HTTP主要用于b/s架构,而RPC更多用于c/s架构。但现在其实已经没分那么清了,b/s和c/s在慢慢融合。很多软件同时支持多端,所以对外一般用HTTP协议,而内部集群的微服务之间则采用RPC协议进行通讯。
TCP 协议本身是全双工的,但我们最常用的 HTTP/1.1,虽然是基于 TCP 的协议,但它是半双工的,对于大部分需要服务器主动推送数据到客户端的场景,都不太友好,因此我们需要使用支持全双工的 WebSocket 协议。
在 HTTP/1.1 里,只要客户端不问,服务端就不答。基于这样的特点,对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送(comet)的效果。
对于客户端和服务端之间需要频繁交互的复杂场景,比如网页游戏,都可以考虑使用 WebSocket 协议。
WebSocket 和 socket 几乎没有任何关系,只是叫法相似。
正因为各个浏览器都支持 HTTP协 议,所以 WebSocket 会先利用HTTP协议加上一些特殊的 header 头进行握手升级操作,升级成功后就跟 HTTP 没有任何关系了,之后就用 WebSocket 的数据格式进行收发数据。
TCP 实现可靠传输的方式之一,是通过序列号与确认应答。
在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个确认应答消息,表示已收到消息。
TCP 会在以下两种情况发生超时重传:
数据包丢失
确认应答丢失
TCP 还有另外一种快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。
在上图,发送方发出了 1,2,3,4,5 份数据:
第一份 Seq1 先送到了,于是就 Ack 回 2;
结果 Seq2 因为某些原因没收到,Seq3 到达了,于是还是 Ack 回 2;
后面的 Seq4 和 Seq5 都到了,但还是 Ack 回 2,因为 Seq2 还是没有收到;
发送端收到了三个 Ack = 2 的确认,知道了 Seq2 还没有收到,就会在定时器过期之前,重传丢失的 Seq2。
最后,收到了 Seq2,此时因为 Seq3,Seq4,Seq5 都收到了,于是 Ack 回 6 。
所以,快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
引入窗口概念的原因
我们都知道 TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。
这个模式就有点像我和你面对面聊天,你一句我一句。但这种方式的缺点是效率比较低的。
如果你说完一句话,我在处理其他事情,没有及时回复你,那你不是要干等着我做完其他事情后,我回复你,你才能说下一句话,很显然这不现实。
所以,这样的传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低。
为解决这个问题,TCP 引入了窗口这个概念。即使在往返时间较长的情况下,它也不会降低网络通信的效率。
那么有了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。
假设窗口大小为 3 个 TCP 段,那么发送方就可以「连续发送」 3 个 TCP 段,并且中途若有 ACK 丢失,可以通过「下一个确认应答进行确认」。如下图:
图中的 ACK 600 确认应答报文丢失,也没关系,因为可以通过下一个确认应答进行确认,只要发送方收到了 ACK 700 确认应答,就意味着 700 之前的所有数据「接收方」都收到了。这个模式就叫累计确认或者累计应答。
发送方不能无脑的发数据给接收方,要考虑接收方处理能力。
如果一直无脑的发数据给对方,但对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪费。
为了解决这种现象发生,TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是所谓的流量控制。