七层网络模型
OSI 和TCP/IP 的对应关系和协议

TCP/IP参考模型就4层即支持网络传输的TCP/IP协议族可以分为四大块 应用层:HTPP协议->传输层:TCP和UDP->网络层: IP协议->链路层
五层因特网协议栈:
- 应用层(dns,http) DNS解析成IP并发送http请求(提供应用程序间通信)
- 传输层(tcp,udp) 建立tcp连接(三次握手)(建立主机端到端链接)
- 网络层(IP,ARP) IP寻址(寻址和路由选择)
- 数据链路层(PPP) 封装成帧(提供介质访问,链路管理等)
- 物理层(利用物理介质传输比特流) 物理传输(然后传输的时候通过双绞线,电磁波等各种介质)
OSI模型各层的基本作用
- 应用层:为应用程序提供网络服务
- FTP:文件传输协议,用来在客户机和FTP服务器之间传输文件
- DNS域名系统:提供域名到IP地址之间的解析服务
- SMTP:邮件发送协议,用户通过SMTP服务器发送邮件
- DHCP:动态主机配置协议,DHCP服务器为客户机动态分配IP地址
- POP3:邮件接收协议,用于从POP3服务器接收邮件
- 表示层:数据格式化,加密,解密
- 会话层:建立,维护,管理会话连接
- 传输层:建立,维护,管理端到端的连接

- 网络层:ip寻址和路由选择
6. 数据链路层:控制网络层和物理层之间通信
7. 物理层:比特流传输,0和1

http 超文本传输协议
超文本传输协议:它是一个基于 TCP/IP 通信协议来传输数据的应用层协议
HTTP是在应用的一个协议,本身就是一个协议,是从web服务器传输超文本到本地浏览器的传输协议
HTTP协议基于请求/响应模型的,并且是TCP协议的
HTTP连接最显著的特点是客户端发送的每次请求都需要回送响应,在请求结束后会主动释放连接,从建立连接到关闭连接的过程称为‘一次连接’
- HTTP通常跑在TCP/IP协议栈之上,依靠IP协议实现寻址和路由、TCP协议实现可靠数据传输、DNS协议实现域名查找、SSL/TLS协议实现安全通信
- HTTP存在的位置:处于 TCP/IP 网络分层模型中的第一层「应用层」
特点及缺点
- HTTP协议支持客户端/服务端模式,也是一种请求/响应模式的协议
- 灵活可扩展:一个是语义上的自由,只规定了基本格式,其它的各部分没有严格的限制;第二个它允许传输任意类型的数据对象,例如文本、图片、音频等,传输的类型由Content-Type加以标记
- 可靠传输,HTTP 基于 TCP/IP,因此把这一特性继承了下来
- 无状态,即HTTP请求不具备保存之前发送过的请求或响应的功能,每一次请求都是独立无关的
HTTP协议是一种不保存状态的协议、自身不对请求和响应之间的通讯状态进行保存,也就是说HTTP这个级别,对于发送过的请求或响应都不做持久化处理,每次请求响应都是全新的都是独立的、(不需要记录状态,服务端减小CPU、内存资源消耗)
- 持久链接
- 概念:建立一次TCP连接即可进行多次请求或响应的交互
- 产生原因:HTTP的初始版本是每进行一次HTTP通信就要断开一次TCP连接,下次再进行时又要重新连接断开。再如今请求的资源越来越大,每次请求如果都有无谓TCP连接和断开是很大的开销
- 特点:只要有一方没有明确的提出断开连接,则保持TCP连接状态
- 优点:减少了TCP连接和断开的造成的额外开销,减轻了服务端的负载,Web页面加载变快
- 注意点:在HTTP/1.1中所有的连接默认都是持久连接的(也就是首部字段 Connection: keep-alive,若是想要关闭则将值设置为 close),但是HTTP/1.0并未标准化
-
keep-alive的作用 在早期的HTTP/1.0中,每次http请求都要创建一个连接,每进行一次HTTP通信都要断开一次TCP连接,断开就意味着如果再次连接就要再次进行三次握手,就要消耗资源 而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,后来就添加了持久连接,在http请求头中加入
Connection: keep-alive来告诉对方这个请求响应完成后不要断开连接,则保持TCP连接状态即一次握手可以通信多次 下一次还用这个请求继续交流- 较少的CPU和内存的使用(由于同时打开的连接的减少了)
- 允许请求和应答的HTTP管线化
- 降低拥塞控制 (TCP连接减少了)
- 减少了后续请求的延迟(无需再进行握手)
- 报告错误无需关闭TCP连
那为啥聊天软件用的还是scoket不用http呢
因为scoket建立长连接后可以是双向通信的,客户端可以给服务端发,服务端也可以给客户端发,而HTTP只能是单向的,所以还得用socket
socket:HTTP属于应该用层,TCP属于传输层,平时用的HTTP请求是直接操作的HTTP,然后HTTP去帮调用TCP,没有直接去调用TCP,Scoket可以看做是对tcp的封装,便于直接调用)

-
缺点:
- 明文传输(不加密),内容可能被窃听:协议里的报文不使用二进制数据,而是文本形式
- 无法验证报文的完整性,内容可能被篡改
指信息的准确度 因为接收方或者发送方没有办法确认对方发送过来的数据在中间有没有被篡改
- 不验证通信方的身份,有可能遭遇伪装
HTTP协议中不会对通信方进行确认 任何人都可以发送请求,而且服务器它对收到的请求也不会进行确认,只要收到了请求就会返回一个响应(当然这个只是在发送端的IP地址或者端口号没被Web服务器设定限制访问的前提下)
- 无状态,它是缺点也是优点吧,分不同的场景
- 对于一些长连接的场景需要保存上下文信息,以免传输重复的数据。
- 对于一些应用只是为了获取数据不需要保存上下文信息,无状态减少了网络开销。
- 队头阻塞
- 其根本原因在于HTTP是基于 请求-响应 的模型,在同一个TCP长连接中,前一个请求没有得到响应,后面的请求就会被阻塞
- 用并发连接 和 域名分片 来解决了这个问题。但并不是从HTTP本身的层面来解决的,只是增加了 TCP 连接,分摊风险而已
- HTTP/2中的多路复用从HTTP本身的层面解决了这个问题
- 和TCP队头阻塞的区别:TCP传输的单位是数据包,它的队头阻塞表示的是前一个报文没有收到便不会将下一个报文上传给HTTP。而HTTP队头阻塞是在 请求-响应 层面,前一个请求还没有处理完,后面的请求就被阻塞
请求方法
- GET:获取资源,幂等操作:不应该有副作用
- HEAD:获取报文首部,和GET很像但是不返回报文主体,幂等操作
- POST: 创建或更新资源,非幂等操作
HTTP响应中应包含帖子的创建状态以及帖子的URI。两次相同的POST请求会在服务器端创建两份资源,它们具有不同的URI,所以POST是「非幂等」的
- PUT: 创建或更新资源本身,幂等操作
第一次PUT方法执行之后,其在服务器上生成的资源,不能被后续的PUT方法更改,所以对同一URI进行多次PUT的副作用和一次PUT是相同的,因而它是「幂等」的、、、 POST,PUT都可用于创建和更新资源,只不过本质的差别就在于幂等性上。POST所对应的URI并非创建资源的本身,而是「资源的接收者」
- PATCH:对资源进行局部更新,非幂等操作
- DELETE:删除资源,和PUT功能相反,幂等操作
删除资源、有副作用(意思就是会修改服务器上的资源内容),但它却是「幂等」的,但对系统产生的副作用的是相同的,因此,调用者可以多次调用或刷新页面而不必担心引起错误
- OPTIONS:查询服务器端支持的HTTP方法种类(幂等操作)
为了获取服务器支持的方法,我知道的一般是使用了代理然后进行一个预请求的时候会用到。它是「幂等」的
正式跨域之前,会发起option请求,预检一下。检测发送的请求是否安全,同时发送请求地址,请求方法,服务器判断来源域名是否再许可名单内,请求方法支不支持,支持则允许请求 复杂请求才会发送预检,以下为复杂请求
- put/delete/patch/post的其中一种
- 发送json格式(content-type: application/json)
- 请求中有自定义头部
为什么要进行预检? 复杂请求可能会对服务器产生副作用,数据修改等。所以要检测一下请求来源在不在许可名单上
- CONNECT:建立连接隧道,用于代理服务器,幂等操作
- TRACE:追踪请求,查询发出去的请求是怎样被加工/篡改的,幂等操作。容易引发XST跨站追踪攻击
一个方法是不是幂等,其实就是判断一个方法重复执行多次,产生的效果是不是一样的,如果是幂等的话,它本质上意味着成功执行请求的结果和它的执行次数无关。我所知道的,只有「POST」和「PATCH」是非幂等的,其它都是幂等操作
状态码
- 1xx 信息性
「请求已经接收到,需要进一步处理才能完成,但是HTTP/1.0 不支持」 101 Switching Protocols :在HTTP升级为WebSocket时,如果服务器同意变更,则返回 101
- 2xx 成功状态:成功处理请求
- 200 OK表示从客户端发来的请求在服务器端被正确处理,通常返回的数据中带有响应体
- 201 Created 请求已经被实现,且有新资源已依据请求的需要而建立
- 202 Accepted 请求已接受,但还没执行,不保证完成请求
- 204 No Content:和200一样,但响应报文不含实体的主体部分
- 206 Partial Content:客户端进行了范围请求且服务端正常处理,响应报文的首部应该还有Content-Range字段指定实体的范围。使用场景为HTTP分块下载和断点续传
- 3xx 重定向:重定向状态,资源位置发生变动,需要重新请求
临时重定向:302、303、307、、永久重定向:301
- 301:永久,最新的URI为响应报文首部的 Location 字段、场景:网站换了地址了,之前的地址不用了,若用户还是从之前的地址进的话则会返回301且在Location中带上最新的URI。且浏览器默认会做缓存优化,减少服务器压力,在第二次访问的时候自动访问重定向的那个地址
- 302 Found:临时,和301不同,表示请求的资源临时被移动到了别的URI上,因为是暂时的,所以不会被缓存
- 303:临时,请求的资源临时被移动到了别的URI上,但明确表示客户端应该使用GET方法获取资源
- 304 Not Modefied:客户端带条件请求时虽未满足条件但也允许返回该资源,虽被划分在3xx中但和重定向没关系。场景:协商缓存成功就会返回304 Not Modefied,表示请求的资源在服务器上并未发送改变,告诉请求者可以使用缓存
- 307:临时,比302更加明确,重定向的请求方法和实体都不允许变动。场景:HSTS协议,强制客户端使用https建立连接,网站从HTTP升级到了HTTPS,而你还是通过http访问的话就会返回307
- 4xx 客户端错误
- 400:请求报文中存在语法错误,但是没有具体指出是哪里
- 401:需要有通过HTTP认证的认证信息或者表示用户认证失败
- 403:请求资源被拒绝,原因是:比如法律禁止、信息敏感
- 404:请求资源未找到,表示没在服务器上找到相应的资源
- 408:客户端请求超时,服务器等待了太长时间
- 409:请求的资源可能引起冲突
- 413:请求体的数据过大
- 429:客户端发送的请求过多
- 5xx 服务端出现错误
- 500 :服务器内部错误,但是没有具体指出是哪里,和400有点像
- 501 :表示客户端请求的功能还不支持
- 502 :服务器自身是正常的,但代理服务器无法获取到合法响应
- 503 :服务器内部处于超负载状态或进行停机维护
HTTP2
在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream) 。
帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。
HTTP2 采用二进制数据帧传输,取代了 HTTP1.x 的文本格式,二进制格式解析更高效。
二进制分帧
帧: HTTP/2 数据通信的最小单位消息:指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息由一个或多个帧组成
HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。 HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。 每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装
在应用层跟传送层之间增加了一个二进制分帧层(二进制协议解析起来更高效),改进传输性能,实现低延迟和高吞吐量
服务器推送
服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源(如下图所示),而无需客户端明确地请求
服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求
服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端
头部压缩
HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,因为它们需要等待带着ACK的响应回来以后才能继续被发送。HTTP/2对消息头采用HPACK(专为http/2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络的流量。而HTTP/1.x每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。
HTTP每一次通信都会携带一组头部,用于描述这次通信的的资源、浏览器属性、cookie等
为了减少这块的资源消耗并提升性能, HTTP/2对这些首部采取了压缩策略:
- HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
- 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
- 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
HTTP/1.x会在请求和响应中中重复地携带不常改变的、冗长的头部数据,给网络带来额外的负担
HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送
首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
tips:可理解为只发送差异数据,而不是全部发送,从而减少头部的信息量
下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销

多路复用
主要原理和工作流程:
- 客户端和服务器之间建立一条TCP连接,该连接可以承载多个并发的HTTP请求和响应。
- 在多路复用模式下,客户端可以同时发起多个HTTP请求,这些请求会被切割成一系列的数据帧,并以无序的方式发送到服务器。
- 服务器接收到这些数据帧后,可以并行处理它们,并以无序的方式发送相应的HTTP响应数据帧。
- 当客户端接收到数据帧后,会根据帧的标识对它们进行重组,还原成完整的HTTP请求和响应。
从 Http/0.9 到 Http/2 要发送多个请求,从多个 Tcp 连接=>keep-alive=>管道化=>多路复用不断的减少多次创建 Tcp 等等带来的性能损耗
发展历程:
Keep-Alive:解决的核心问题是: 一定时间内,同一域名多次请求数据,只建立一次 HTTP 请求,其他请求可复用每一次建立的连接通道,以达到提高请求效率的问题
keep-alive的优点:
- 较少的CPU和内存的使用(由于同时打开的连接的减少了)
- 允许请求和应答的HTTP管线化
- 降低拥塞控制 (TCP连接减少了)
- 减少了后续请求的延迟(无需再进行握手)
- 报告错误无需关闭TCP连
一个tcp/ip连接可以请求多个资源
设置http的header:Connection: keep-alive中开启(1.0默认关闭,1.1默认开启),告诉服务器,待会还要请求,就可以避免tcp再次三次握手了
Keep-Alive还是存在如下问题:
- 串行的文件传输。
- 同域并行请求限制带来的阻塞(6~8)个
多个Tcp连接:
在最早的时候没有keep-alive只能创建多个Tcp连接来做多次请求。一次请求完成就会关闭本次的 Tcp 连接,下个请求又要从新建立 Tcp 连接传输完成数据再关闭,造成很大的性能损耗
多路复用:多路复用代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP 连接并发完成。因为在多路复用之前所有的传输是基于基础文本的,在多路复用中是基于二进制数据帧的传输、消息、流,所以可以做到乱序的传输。多路复用对同一域名下所有请求都是基于流,所以不存在同域并行的阻塞
多路复用代替了 HTTP1.x 的序列和阻塞机制,所有的相同域名请求都通过同一个 TCP 连接并发完成。同一 Tcp 中可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
优点和特点包括:
避免了队头阻塞:在传统的HTTP/1.1中,如果一个请求被阻塞或延迟,后续的请求也会被阻塞,导致队头阻塞。而通过多路复用,即使某个请求被阻塞,其他请求依然可以继续进行,避免了队头阻塞问题。
提高并行处理能力:HTTP多路复用允许服务器并发处理多个请求,客户端也可以同时发送多个请求,充分利用带宽和资源,提高了并行处理能力和效率。
减少连接数量:HTTP多路复用在同一TCP连接上进行多个请求和响应,减少了连接的建立和拆除次数,降低了延迟和资源占用。
头部压缩:HTTP/2还引入了头部压缩技术,可以减少重复的头部信息,进一步提高传输效率。
请求优先级
把HTTP消息分解为很多独立的帧之后,就可以通过优化这些帧的交错和传输顺序,进一步提升性能。为了做到这一点,每个流都可以带有一个31比特的优先值:
- 0 表示最高优先级。
- 231 -1表示最低优先级。
有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。具体来讲,服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。
浏览器在渲染页面时,并非所有资源都具有相同的优先级:HTML文档本身对构建DOM不可或缺,CSS对构建CSSOM不可或缺,而DOM和CSSOM的构建都可能受到JavaScript资源的阻塞(参见10.1节的附注栏“DOM、CSSOM和JavaScript”),其他资源(如图片)的优先级都可以降低。
为加快页面加载速度,所有现代浏览器都会基于资源的类型以及它在页面中的位置排定请求的优先次序,甚至通过之前的访问来学习优先级模式——比如,之前的渲染如果被某些资源阻塞了,那么同样的资源在下一次访问时可能就会被赋予更高的优先级。
在HTTP 1.x中,浏览器极少能利用上述优先级信息,因为协议本身并不支持多路复用,也没有办法向服务器通告请求的优先级。此时,浏览器只能依赖并行连接,且最多只能同时向一个域名发送6个请求。于是,在等连接可用期间,请求只能在客户端排队,从而增加了不必要的网络延迟。理论上,HTTP管道可以解决这个问题,只是由于缺乏支持而无法付诸实践。
HTTP/2 一举解决了所有这些低效的问题:浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。
如果服务器不理睬所有优先值,那么可能会导致应用响应变慢:浏览器明明在等关键的CSS和JavaScript,服务器却在发送图片,从而造成渲染阻塞。不过,规定严格的优先级次序也可能带来次优的结果,因为这可能又会引入队首阻塞问题,即某个高优先级的慢请求会不必要地阻塞其他资源的交付。
服务器可以而且应该交错发送不同优先级别的帧。只要可能,高优先级流都应该优先,包括分配处理资源和客户端与服务器间的带宽。不过,为了最高效地利用底层连接,不同优先级的混合也是必需的。
有了新的分帧机制后,HTTP/2 不再依赖多个TCP连接去实现多流并行了。现在,每个数据流都拆分成很多帧,而这些帧可以交错,还可以分别优先级。于是,所有HTTP/2 连接都是持久化的,而且客户端与服务器之间也只需要一个连接即可。
http3.0
tcp/udp
TCP/IP 是互联网相关的各类协议族的总称,比如:TCP,UDP,IP,FTP,HTTP,ICMP,SMTP 等都属于 TCP/IP 族内的协议
tcp
TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。 一个TCP连接必须要经过三次“对话”才能建立起来 TCP三次握手过程:
- 客户端发送一个含有同步序列号的标识位的数据段SYN给服务端,向服务端请求建立连接、请求发送后,客户端便进入 SYN-SENT 状态。
- 服务端接收到请求后,用一个带有确认应答(ACK)合同部序列号(SYN)标志位的数据段响应客户端,发送完成后便进入 SYN-RECEIVED 状态。
- 客户端收到这个数据段后再发送ACK给服务端确认已经收到服务端的数据段,客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功
这样3次握手就完成了,客户端和服务端就可以传递数据了
3次握手的特点: 没有应用层的数据 ,SYN这个标志位只有在TCP建立连接时才会被置1 ,握手完成后SYN标志位被置0。
为什么不是两次? 这是为了防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误。
为什么不是四次? 三次握手的目的是确认双方发送和接收的能力,那四次握手可以嘛?当然可以,100 次都可以。但为了解决问题,三次就足够了,再多用处就不大了
三次握手过程中可以携带数据么? 第三次握手可以携带。前两次握手不能携带数据
如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。
第三次握手的时候,客户端已经处于ESTABLISHED状态,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据
TCP是一个面向连接的、可靠的、基于字节流的传输层协议、核心:
- 面向连接。指客户端和服务器的连接,在双方互相通信之前,TCP 需要三次握手建立连接,而 UDP 没有相应建立连接的过程
- 可靠性。TCP 花了非常多的功夫保证连接的可靠,这个可靠性体现在哪些方面呢?一个是有状态,另一个是可控制
TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。这是有状态。 当意识到丢包了或者网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的发送速度或者重发。这是可控制
相应的,UDP 就是无状态, 不可控的
- 面向字节流。UDP 的数据传输是基于数据报的,这是因为仅仅只是继承了 IP 层的特性,而 TCP 为了维护状态,将一个个 IP 包变成了字节流
- 四次挥手
- 当客户端完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求 ;
- 服务端收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1;
- 由服务端再提出反方向的关闭请求,将FIN置1 ;
- 客户端对服务端的请求进行确认,将ACK置1,双方向的关闭结束.。
1、ACK 是TCP报头的控制位之一,对数据进行确认。确认由目的端发出, 用它来告诉发送端这个序列号之前的数据段都收到了。 比如确认号为X,则表示前X-1个数据段都收到了,只有当ACK=1时,确认号才有效,当ACK=0时,确认号无效,这时会要求重传数据,保证数据的完整性。
2、SYN 同步序列号,TCP建立连接时将这个位置1。
3、FIN 发送端完成发送任务位,当TCP完成数据传输需要断开时,,提出断开连接的一方将这位置1。
由TCP的三次握手和四次断开可以看出,TCP使用面向连接的通信方式, 大大提高了数据通信的可靠性,使发送数据端和接收端在数据正式传输前就有了交互, 为数据正式传输打下了可靠的基础。
为什么是四次挥手而不是三次?
因为服务端在接收到FIN, 往往不会立即返回FIN, 必须等到服务端所有的报文都发送完毕了,才能发FIN。因此先发一个ACK表示已经收到客户端的FIN,延迟一段时间才发FIN。这就造成了四次挥手
如果是三次挥手会有什么问题?
等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端,从而让客户端不断的重发FIN
UDP 用户数据报协议
UDP是传输层的协议,功能即为在IP的数据报服务之上增加了最基本的服务:复用和分用以及差错检测。
- UDP无连接,没有三次握手,四次挥手,想法数据就可发,不会对数据报文进行任何拆分和拼接操作,UDP不维护连接状态,也不跟踪这些参数,开销小。空间和时间上都具有优势
- 分组首部开销小**,TCP首部20字节,UDP首部8字节。
- UDP没有拥塞控制,应用层能够更好的控制要发送的数据和发送时间,网络中的拥塞控制也不会影响主机的发送速率。某些实时应用要求以稳定的速度发送,能容 忍一些数据的丢失,但是不能允许有较大的时延(比如实时视频,直播等)
- UDP提供尽最大努力的交付,不保证可靠交付。所有维护传输可靠性的工作需要用户在应用层来完成。没有TCP的确认机制、重传机制。如果因为网络原因没有传送到对端,UDP也不会给应用层返回错误信息
- UDP常用一次性传输比较少量数据的网络应用,如DNS,SNMP等,因为对于这些应用,若是采用TCP,为连接的创建,维护和拆除带来不小的开销。UDP也常用于多媒体应用(如IP电话,实时视频会议,流媒体等)数据的可靠传输对他们而言并不重要,TCP的拥塞控制会使他们有较大的延迟,也是不可容忍的
- UDP是面向报文的
- 发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文
- UDP提供不可靠服务
- 首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。并且收到什么数据就传递什么数据,
- 并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。
- 再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。
丢包原因和处理:
TCP与UDP的区别:
- tcp建立连接与udp无连接;
- tcp请求多了会造成阻塞,udp不会
- 连接对象个数:tcp是1v1的。udp是1v1,多对1,1对多,多对多
- 对系统资源的要求(TCP较多,UDP少);
- UDP程序结构较简单;
- 流模式与数据报模式 ;
- tcp可靠传输,使用流量控制和拥塞控制。udp不可靠传输,不是用流量控制和拥塞控制
- TCP保证数据正确性,UDP可能丢包
- TCP保证数据顺序,UDP不保证
- 适用场景:tcp适用于要求可靠传输的应用比如文件传输、udp适用于实时应用(Ip电话,视频会议,直播等)
- 传输方式:tcp面向字节流,udp面向报文
https
https是安全版的http,因为http协议的数据都是明文进行传输的,所以对于一些敏感信息的传输就很不安全,HTTPS就是为了解决HTTP的不安全而生的
概念
通信接口部分用SSL/TLS协议替代(在HTTP和TCP之间建立中间层)。即HTTPS其实就是身披SSL协议这层外壳的HTTP:HTTPS = HTTP + SSL/TLS
与HTTP区别
- HTTPS标准端口443,HTTP是80
- HTTPS基于传输层,HTTP基于应用层
- 数据隐私性,内容经过对称加密;
- 数据完整性,内容经过完整性校验;
- 身份认证,第三方无法伪装客户端/服务器的身份
https是如何保证安全的
对称加密:即通信的双方都使用同一个秘钥进行加解密,就属于对称加密,该方法虽然很简单性能也好,但是无法解决首次把秘钥发给对方的问题,很容易被hacker拦截秘钥
非对称加密:
- 私钥 + 公钥= 密钥对
- 用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密
- 因为通信双方的手里都有一套自己的密钥对,通信之前双方会先把自己的公钥都先发给对方
- 然后对方再拿着这个公钥来加密数据响应给对方,等到了对方那里,对方再用自己的私钥进行解密
非对称加密虽然安全性更高,但是带来的问题就是速度很慢,影响性能
解决方法:https结合两种加密方式,将对称加密的密钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用私钥进行解密得到对称加密的密钥,然后双方可以使用对称加密来进行沟通
过程如下:
- 客户端首先向服务端发送一个HTTPS请求
- 服务端会把事先配置好的公钥证书随着其它的信息返回给客户端
- 客户端在收到服务端发来的证书之后进行验证,验证的过程参考数字证书验证,会得到服务端的信息以及它的公钥
- 验证成功之后生成一个叫做 client_params 的参数发送给服务器;同时自己会用伪随机函数生成一个secret,这个secret就是它们后续进行通信的对称密钥。
- 服务器在收到刚刚的client_params之后,也会根据伪随机函数生成一个secret。这时候双方都有了相同的对称密钥。
- 后面的传输都会用这个secret进行对称密钥加解密传输
TCp粘包问题分析与对策
粘包情况有两种,一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包
原因:
- 简单得说,在流传输中出现,UDP不会出现粘包,因为它有消息边界
- 发送端需要等缓冲区满才发送出去,造成粘包
- 接收方不及时接收缓冲区的包,造成多个包接收
具体点:
(1)发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据
(2)接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
不是所有的粘包现象都需要处理,若传输的数据为不带结构的连续流数据(如文件传输),则不必把粘连的包分开(简称分包)。但在实际工程应用中,传输的数据一般为带结构的数据,这时就需要做分包处理。
在处理定长结构数据的粘包问题时,分包算法比较简单;在处理不定长结构数据的粘包问题时,分包算法就比较复杂。特别是粘在一起的包有不完整的包的粘包情况,由于一包数据内容被分在了两个连续的接收包中,处理起来难度较大。实际工程应用中应尽量避免出现粘包现象
为了避免粘包现象,可采取以下几种措施:
(1)对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;
虽然可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用
(2)对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;
只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包
(3)由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包
虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合
TCP无保护消息边界的解决、针对这个问题,一般有3种解决方案:
- 发送固定长度的消息
- 把消息的尺寸与消息一块发送
- 使用特殊标记来区分消息间隔
同源策略
如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”
同源策略限制内容有:
- Cookie、LocalStorage、IndexedDB 等存储性内容
- DOM 节点
- AJAX 请求发送后,结果被浏览器拦截了 有三个标签是允许跨域加载资源: img、link、script
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了
跨域方案
JSONP
实现原理
利用script没有跨域限制,网页可得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以
和AJAX对比
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
//在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP函数。
// index.html
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
window[callback] = function(data) {
resolve(data)
document.body.removeChild(script)
}
params = { ...params, callback } // wd=b&callback=show
let arrs = []
for (let key in params) {
arrs.push(`${key}=${params[key]}`)
}
script.src = `${url}?${arrs.join('&')}`
document.body.appendChild(script)
})
}
jsonp({
url: 'http://localhost:3000/say',
params: { wd: 'Iloveyou' },
callback: 'show'
}).then(data => {
console.log(data)
})
nginx反向代理
- 反向代理 将请求发送到服务器,然后服务器对我们的请求进行转发,只需要和代理服务器进行通信就好
- 正向代理 对于目标服务器来讲,感受不到真实的客户端,与它通信的是代理客户端,如科学谷歌的软件就是一个正向代理
简单概括:服务器代理被称为反向代理,客户端代理被称为正向代理
WebSocket与HTTP的关系
相同点:
- 都是应用层的通信协议
- 默认端口一样,都是80或443
- 都可以用于浏览器和服务器间的通信
- 都基于TCP协议,都是可靠性传输协议
不同点:
- HTTP的协议标识符是http,websocket的是ws
- HTTP请求只能由客户端发起,服务器无法主动向客户端推送消息,而websocket可以
- HTTP请求有同源限制,不同源之间通信需要跨域,而websocket没有同源限制
联系:WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的
WebSocket与长轮询有什么区别
长轮询就是客户端发起一个请求,服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断请求的数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则等待一定的时间后才返回。
长轮询的本质还是基于 HTTP 协议,它仍然是一个一问一答(请求 — 响应)的模式。而 WebSocket 在握手成功后,就是全双工的 TCP 通道,数据可以主动从服务端发送到客户端
webSocket心跳
心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息,如果服务端几分钟内没有收到客户端信息则视客户端断开
在 WebSocket 协议中定义了 心跳 Ping 和 心跳 Pong 的控制帧:
- 心跳 Ping 帧包含的操作码是 0x9。如果收到了一个心跳 Ping 帧,那么终端必须发送一个心跳 Pong 帧作为回应,除非已经收到了一个关闭帧。否则终端应该尽快回复 Pong 帧。
- 心跳 Pong 帧包含的操作码是 0xA。作为回应发送的 Pong 帧必须完整携带 Ping 帧中传递过来的 “应用数据” 字段。如果终端收到一个 Ping 帧但是没有发送 Pong 帧来回应之前的 Ping 帧,那么终端可以选择仅为最近处理的 Ping 帧发送 Pong 帧。此外,可以自动发送一个 Pong 帧,这用作单向心跳。
WebSocket的优点
- 支持双向通信,实时性更强(聊天)。
- 由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据
- 较少的控制开销(连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较少)
- WebSocket 只需要一次握手,在每次传输数据时只传输数据帧即可。而 HTTP 协议下,每次请求都需要携带完整的请求头信息,例如 User-Agent、Referer 和 Host 等。所以 WebSocket 的开销相对于 HTTP 来说会少很多
- 数据格式比较轻量,性能开销小,通信高效、 协议控制的数据包头部较小,而HTTP协议每次通信都需要携带完整的头部
- 更好的二进制支持
- WebSocket 定义了二进制帧,可以更轻松地处理二进制内容
- 没有同源限制,客户端可以与任意服务器通信
- 长连接,保持连接状态
- 与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)
- 更好的压缩
- Websocket 在适当的扩展支持下,可以沿用之前内容的上下文。这样在传递类似结构的数据时,可以显著地提高压缩率
- 支持扩展:开发者可以扩展协议,或者实现部分自定义的子协议
- 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器
输入url到展示的过程
- 浏览器先检查本地的缓存中是否有对应的域名,有就根据ip与服务器建立链接,若无则进入下一步的网络请求流程
- DNS域名解析:获取待请求域名的ip地址(解析http协议,端口号,资源地址),若请求协议是https那还需要建立tls链接、、dns解析时,会按本地浏览器缓存->本地host文件->路由器缓存->dns服务器->根、dns服务器的顺序查询域名对应的ip地址,知道找到为止
- 浏览器与服务器ip地址建立tcp链接,建立链接后浏览器端会构建请求行,请求头信息,并把和该域名相应的cookie等数据附加到请求头中,向服务器发送构建的请求信息
- 发起http请求,3次握手
- 服务器响应请求并返回结果:服务器对浏览器请求作出响应,并把对应的html文件发给浏览器
- 关闭tcp链接,4次挥手
- 浏览器渲染:浏览器解析html内容并渲染出来
渲染过程:构建dom树,词法分析然后解析dom tree由dom元素及属性节点,组成树的根是document对象
构建cs规则树,构建render树:dom和css合并构建render tree
布局layout:浏览器计算网页中有哪些节点,各节点的css及从属关系->回流
绘制painting:根据render tree回流得到节点信息,计算出每个节点在屏幕的位置->重绘,最后把信息交给图形处理程序显示页面
- 回流(Reflow):回流比重绘的代价要更高、回流必将引起重绘,重绘不一定会引起回流
当 Render Tree 中部分或全部元素的尺寸、结构、属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流 页面首次渲染
流程是:修改CSSOM树-->更新渲染树-->重布局-->重绘制
操作:浏览器窗口大小发生改变、、元素尺寸或位置发生改变元素内容变化、元素字体大小变化、增删可见的DOM元素、激活 CSS 伪类(:hover)、查询某些属性或调用某些方法(offsetTop, clientTop,,,,)
- 重绘(Repaint)
页面中元素样式的改变并不影响它在文档流中的位置时(如:color、background-color、visibility 等),浏览器不需重 新计算元素的几何属性、直接为该元素绘制新的样式,流程是:修改CSSOM树-->更新渲染树-->重绘制
cookie、sessionStorage、localStorage
都不能跨域都在本地浏览器中缓存
- 存放数据大小不同:cookie是4k左右,另外2个一般是5M
- 与服务器端通信:sessionStorage、localStorage仅在客户端中保存,不和serve通信、cookie每次都会携带在http头中发给server,但使用cookie保存过多数据会带来性能问题
- 数据的生命周期不同:
- cookie一般由serve生成,可设置失效时间,若在浏览器端生成cookie默认是关闭浏览器后失效,过期时间前一直有效
- sessionStorage仅在当前会话下有效,关闭页面或浏览器被清除后,页面刷新不会消除数据,页面打开的链接才可访问sessionStorage的数据
- localStorage 永久保存即使是关闭浏览器也不会让数据消失,除非主动删除
GET和POST的区别
- GET - 从指定的资源请求数据。
- POST - 向指定的资源提交要被处理的数据
- 缓存:GET会被浏览器主动缓存下来,留下历史记录,但POST不会,刷新后退数据会被重新提交
- 数据类型:GET只能进行URL编码,它只能接收ASCII字符,但POST没有限制支持多种编码方式
- 安全性:
GET把参数包含在URL中,通过历史记录,缓存很容易查到数据信息,POST通过request body传递参数,更适合传递敏感信息 - 数据长度发送数据时,GET方法向url添加数据,URL的长度是受限制的(URL的最大长度是2048个字符),POST无限制
- 链接:两者本质都是tcp链接,并无差别。但由于HTTP的规定和浏览器/服务器的限制,导致它们在应用过程中体现出一些不同
- tcp:GET产生一个TCP数据包;POST产生两个TCP数据包
- get请求比post快主要是因为:get请求比post请求少一条和get请求可以缓存
http各版本区别:
各版本区别
HTTP/0.9:
功能简陋,只支持GET方法且不支持请求头,只支持纯文本一种内容,服务器只能回应HTML格式的字符串,里边不能插入图片
HTTP/1.0:
根据Content-Type可支持多种数据格式(text/html、application/javascript、image/jpeg,传输文字,图像、音频、视频等二进制文件)
增加POST、HEAD等方法,
增加头信息
每次只能发送一个请求(无持久连接即不支持keepalive)、
支持cache,就是当客户端在规定时间内访问统一网站,直接访问cache即可
HTTP/1.1:
默认持久连接:即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive
请求管道化:(在同一个TCP连接里,允许多个请求同时发送,增加了并发性,进一步改善了HTTP协议的效率)、
新增了请求方式PUT、PATCH、OPTIONS、DELETE、
增加Host字段:用来指定服务器的域名、
支持断点传输分块传输:RANGE:bytes,HTTP/1.0每次传送文件都是从文件头开始,即0字节处开始。RANGE:bytes=XXXX表示要求服务器从文件XXXX字节处开始传送,断点续传。即返回码是206(Partial Content)
HTTP/2.0:二进制分帧、多路复用、头部压缩、
增加双工模式:不仅客户端能够同时发送多个请求,服务端也能同时处理多个请求
多路复用:同一个连接并发处理多个请求,解决了队头堵塞的问题
服务器推送:允许服务器未经请求,主动向客户端发送资源
二进制分帧:头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧,好处是,可以定义额外的帧,
头部压缩:HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的(比如Cookie和User Agent),一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了
小程序为什么会有两个线程?
单点登录 如何一次性渲染十万条数据页面又不卡顿?
|