集线器、网桥、交换机、路由器
- 网线是物理层的硬件
- 集线器(Hub)是物理层的硬件,连接所有的线路,广播所有信息
- 网桥(Bridge)是数据链路层的硬件。网桥隔离两个端口,不同的端口形成单独的冲突域,减少网内冲突。网桥在不同或相同类型的 LAN 之间存储并转发数据帧,根据 MAC 头部来决定转发端口,显然是数据链路层的设备
- 交换机(Switch)是数据链路层的硬件,相当于多端口的网桥。交换机内部存储 MAC 表,只会将数据帧发送到指定的目的地址
- 路由器(Router)是网络层的硬件,根据 IP 地址进行寻址,不同子网间的数据传输隔离
TCP
- TCP头部20个字节,TCP的包是没有IP地址的,那是IP层上的事。但是有源端口和目标端口;UDP 协议头包含 4 个字段:源端口、目的端口、长度和校验码,其中每一个字段都占 2 字节,总长度 8 字节
三次握手
- 客户端请求建立连接,向服务端发送一个同步报文(SYN=1),同时选择一个随机数 seq = x 作为初始序列号
- 服务端收到连接请求报文后,如果同意建立连接,则向客户端发送同步确认报文(SYN=1,ACK=1),确认号为 ack = x + 1,同时选择一个随机数 seq = y 作为初始序列号
- 客户端收到服务端的确认后,向服务端发送一个确认报文(ACK=1),确认号为 ack = y + 1,序列号为 seq = x + 1
为什么是三次握手
- 通信的双方要互相通知对方自己的初始化的Sequence Number,这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序
- 如果只有两次握手,那么服务端向客户端发送 SYN/ACK 报文后,就会认为连接建立。但是如果客户端没有收到报文,那么客户端是没有建立连接的。这就导致服务端会浪费资源。
- 第一次握手:服务端确认“服务端收、客户端发”报文功能正常; 第二次握手:客户端确认“客户端发、客户端收、服务端收、服务端发”报文功能正常,客户端认为连接已建立; 第三次握手:服务端确认“服务端发、客户端收”报文功能正常,此时双方均建立连接,可以正常通信;
SYN 攻击?
SYN 攻击属于 DOS 攻击的一种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。
原理:
在三次握手过程中,服务器发送第二个包之后、收到客户端的第三个包之前的 TCP 连接称为半连接,此时服务器处于 SYN_RECV(等待客户端响应)状态。如果接收到客户端的第三个包,则 TCP 连接成功,如果未接受到,则会不断重发请求直至成功
SYN 攻击的攻击者在短时间内伪造大量不存在的 IP 地址,向服务器不断地发送第一个包,服务器回复第二个包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时
这些伪造的第一个包将长时间占用未连接队列,影响了正常的 SYN,导致目标系统运行缓慢、网络堵塞甚至系统瘫痪。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s
检测:当在服务器上看到大量的半连接状态时,特别是源 IP 地址是随机的,基本上可以断定这是一次 SYN 攻击。
防范:主要有两大类,一类是通过***、路由器等过滤网关防护,另一类是通过加固 TCP/IP 协议栈防范,如增加最大半连接数,缩短超时时间。但 SYN 攻击不能完全被阻止,除非将 TCP 协议重新设计,否则只能尽可能的减轻 SYN 攻击的危害。
四次挥手
-
第一次挥手:客户端向服务端发送连接释放报文(FIN=1,ACK=1),主动关闭连接,同时等待服务端的确认
序列号 seq = u,即客户端上次发送的报文的最后一个字节的序号 + 1;
确认号 ack = k, 即服务端上次发送的报文的最后一个字节的序号 + 1
-
第二次挥手:服务端收到连接释放报文后,立即发出确认报文(ACK=1),序列号 seq = k,确认号 ack = u + 1
这时 TCP 连接处于半关闭状态,即客户端到服务端的连接已经释放了,但是服务端到客户端的连接还未释放。这表示客户端已经没有数据发送了,但是服务端可能还要给客户端发送数据,服务端处于【close_wait】状态。
-
第三次挥手:服务端向客户端发送连接释放报文(FIN=1,ACK=1),主动关闭连接,同时等待客户端的确认
序列号 seq = w,即服务端上次发送的报文的最后一个字节的序号 + 1。如果半关闭状态,服务端没有发送数据,那么 w == k
确认号 ack = u + 1,与第二次挥手相同,因为这段时间客户端没有发送数据
-
第四次挥手:客户端收到服务端的连接释放报文后,立即发出确认报文(ACK=1),序列号 seq = u + 1,确认号为 ack = w + 1
此时,客户端就进入了 TIME-WAIT 状态。注意此时客户端到 TCP 连接还没有释放,必须经过 2*MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态。而服务端只要收到客户端发出的确认,就立即进入 CLOSED 状态。
因为 TCP 是全双工的,一方关闭连接后,另一方还可以继续发送数据。所以四次挥手,将断开连接分成两个独立的过程。
####为什么第四次挥手,客户端的 TIME-WAIT 状态必须等待 2MSL 的时间才能返回到 CLOSED 状态?
- 确保 ACK 报文能够到达服务端,从而使服务端正常关闭连接。
- 防止已失效的连接请求报文段出现在之后的连接中
TCP 要求在 2MSL 内不使用相同的序列号。客户端在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。或者即使收到这些过时的报文,也可以不处理它。
TCP重传机制
ACK & Selective Acknowledgment (SACK) & Duplicate SACK – 重复收到数据的问题
TCP的RTT算法 - Round Trip Time,也就是一个数据包从发出去到回来的时间
Jacobson / Karels 算法
SRTT = SRTT + α (RTT – SRTT) —— 计算平滑RTT
DevRTT = (1-β)DevRTT + β(|RTT-SRTT|) ——计算平滑RTT和真实的差距(加权移动平均)
RTO= µ * SRTT + ∂ *DevRTT —— 神一样的公式
其中:在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4
TCP滑动窗口
TCP头里有一个字段叫Window,又叫Advertised-Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
对于发送端来说:
LastByteAcked 指向被接收端 ACK 的最后一个位置
LastByteSent 指向已发送但还未收到 ACK 的最后一个位置
LastByteWritten 指向上层应用写入但还未发送的最后一个位置
对于接收端来说:
LastByteRead 指向 TCP 缓冲区中读到的位置
NextByteExpected 指向收到的连续包的最后一个位置
LastByteRcvd 指向收到的包的最后一个位置
零窗口
TCP 使用来 ZWP(Zero Window Probe,零窗口探针)技术。具体是在发送端引入一个计时器,每当收到一个零窗口的应答后就启动该计时器。每间隔一段时间就主动发送报文,由接收端来 ACK 窗口大小。若接收者持续返回零窗口(一般是 3 次),则有的 TCP 实现会发送 RST 断开连接。
Nagle 算法:如果接收端处理过慢,每次 window 只能接收几个字节,那么当发送端每次都发送这几个字节时,会有大量带宽浪费在 TCP 和 IP 的首部上。因此 Nagle 提出了 Nagle 算法。Nagle 算法的工作方式是「缓存/累积」要发送的小数据,直到 window >= MSS 时再一并发送,避免对小的 window 作出响应。
TCP的拥塞处理
1)慢启动,2)拥塞避免,3)拥塞发生,4)快速恢复
- 慢热启动算法
连接建立时,初始化 cwnd = 1,表示可以传一个 MSS 大小的数据(最大报文段长度(MSS)是TCP协议的一个选项,用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度(不包括文段头)。)
每收到一个 ACK 包,cwnd++
每经过一个 RTT,cwnd 会翻倍(指数增长)
当 cwnd >= ssthresh (slow start threshold) 时,进入拥塞避免阶段。
- 拥塞避免
每收到一个 ACK 包,cwnd = cwnd + 1/cwnd
每经过一个 RTT,cwnd = cwnd + 1(加性增)
- 超时重传
如果发送端超时还未收到 ACK 包,就可以认为网络出现了拥塞,需要解决拥塞:
把 sshthresh 设为原来的一半(乘性减)
cwnd 重置为 1,重新开始慢启动过程
- 快速重传 & 快速恢复
快速重传:接收端收到乱序包时,会发送 duplicate ACK 通知发送端。当发送端收到 3 个 duplicate ACK 时,就立刻开始重传,而不必继续等待到计时器超时。
快速重传会配合快速恢复算法:
把 sshthresh 设为原来的一半(乘性减)
cwnd 重置为 sshthresh,重新开始拥塞避免过程
为什么快速重传不需要像超时重传那样,将 cwnd 重置为 1 重新开始慢启动呢?因为它认为如果网络出现拥塞的话,是不会收到好几个重复的 ACK 的,所以现在网络可能没有出现拥塞。
TCP和UDP对比
| TCP | UDP | |
|---|---|---|
| 连接性 | 面向连接 | 无连接 |
| 可靠性 | 可靠 | 不可靠 |
| 传输方式 | 面向字节流 | 面向报文(保留报文的边界) |
| 传输速度 | 慢 | 快 |
| 双工性 | 全双工 | 一对一、一对多、多对一、多对多 |
| 流量控制 / 拥塞控制 | 有 | 无 |
| 应用场景 | 对效率要求相对低,但是对准确性要求高的场景;或是要求有连接的场景。如文件传输、发送邮件等 | 对效率要求相对高,对准确性要求相对低的场景。如即时通信、直播等 |
| 应用层协议 | SMTP(电子邮件)、TELNET(远程登录控制)、HTTP、FTP | DNS、TFTP(文件传输)、DHCP(动态主机配置)... |
HTTP
HTTP 请求方法
- GET:获取服务器的指定资源
- HEAD:与 GET 方法一样,都是发出一个获取服务器指定资源的请求,但服务器只会返回 Header 而不会返回 Body。用于确认 URI 的有效性及资源更新的日期时间等。一个典型应用是下载文件时,先通过 HEAD 方法获取 Header,从中读取文件大小 Content-Length;然后再配合 Range 字段,分片下载服务器资源
- POST:提交资源到服务器 / 在服务器新建资源
- PUT:替换整个目标资源
- PATCH:替换目标资源的部分内容
- DELETE:删除指定的资源
幂等的:一个 HTTP 方法是幂等的,指的是同样的请求执行一次与执行多次的效果是一样的。换句话说就是,幂等方法不应该具有副作用。
常见的幂等方法:GET,HEAD,PUT,DELETE,OPTIONS
常见的非幂等方法:POST
安全的:一个 HTTP 方法是安全的,指的是这是一个对服务器只读操作的方法,不会修改服务器数据。
常见的安全方法:GET,HEAD,OPTIONS
常见的不安全方法:PUT,DELETE,POST
| GET | POST | |
|---|---|---|
| 应用 | 获取服务器的指定数据 | 添加 / 修改服务器的数据 |
| 历史记录 / 书签 | 可保留在浏览器历史记录中,或者收藏为书签 | 不可以 |
| Cacheable | 会被浏览器缓存 | 不会缓存 |
| 幂等 | 幂等,不会改变服务器上的资源 | 非幂等,会对服务器资源进行改变 |
| 后退 / 刷新 | 后退或刷新时,GET 是无害的 | 后退或刷新时,POST 会重新提交表单 |
| 参数位置 | query 中(直接明文暴露在链接中) | query 或 body 中 |
| 参数长度 | 2KB(2048 个字符) | 无限制 |
HTTP 状态码
- 信息响应(100–199)
- 100 Continue:表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应
- 成功响应(200–299)
- 200 OK
- 201 Created:该请求已成功,并因此创建了一个新的资源。这通常是在 POST 请求之后返回的响应
- 204 No Content:该请求已成功处理,但是返回的响应报文不包含实体的主体部分。通常用于只需要从客户端往服务器发送信息,而不需要返回数据时
- 206 Partial Content:服务器已经成功处理了部分 GET 请求,该请求必须包含 Range 头信息来指示客户端希望得到的内容范围。通常使用此类响应来实现断点续传,或者将一个大文档分为多个片段然后并行下载
- 重定向(300–399)
- 301 Moved Permanently:永久性重定向
- 302 Found:临时性重定向。常见应用场景是通过 302 跳转将所有的 HTTP 流量重定向到 HTTPS
- 303 See Other:和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源
- 304 Not Modified:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304 响应不包含消息体
- 307 Temporary Redirect:临时重定向。307 与 302 之间的唯一区别在于,当发送重定向请求的时候,307 状态码可以确保请求方法和消息主体不会发生变化;而如果使用 302 响应状态码,一些旧客户端会错误地将请求方法转换为 GET
- 返回的 Header 中有一个 Location 字段指向目标 URL,浏览器会重定向到这个 URL。
- 客户端错误(400–499)
- 400 Bad Request:请求报文中存在语法错误,或者参数有误
- 401 Unauthorized:未认证(没有登录)
- 403 Forbidden:没有权限(登录了但没有权限)
- 404 Not Found
- 405 Method Not Allowed
- 服务器错误 (500–599)
- 500 Internal Server Error:服务器遇到了不知道如何处理的情况
- 502 Bad Gateway:网关错误,作为网关或代理角色的服务器,从上游服务器(如tomcat、php-fpm)中接收到的响应是无效的
- 503 Service Unavailable:服务器无法处理请求,常见原因是服务器因维护或重载而停机
HTTP缓存
浏览器可以将已经请求过的资源(如图片、JS 文件)缓存下来,下次再次请求相同的资源时,直接从缓存读取。
浏览器采用的缓存策略有两种:强制缓存、协商缓存。浏览器根据第一次请求资源时返回的 HTTP 响应头来选择缓存策略。
强制缓存:为资源设置一个过期时间,只要资源没有过期,就读取浏览器的缓存。强制缓存不需要向服务器发起请求,浏览器直接返回 200(from cache)。
协商缓存:浏览器携带缓存资源的元信息,向服务器发起请求,由服务器决定是否使用缓存。如果协商缓存生效,服务器返回 304 和 Not Modified;如果协商缓存失效,服务器返回 200 和请求结果。
协商缓存的原理是:服务端根据资源的元信息,判断浏览器缓存的资源在服务器上是否有改动。元信息有两种,一种是资源的上次修改时间,另一种是资源 Hash 值。前者实现简单,但是精确度低,文件修改时间只能以秒记;后者精确度高,但是性能低,需要计算哈希值。
强缓存由 Expires(和系统时间进行比较,超则失效)、Cache-Control 和 Pragma(只有 no-cache,不缓存)(优先级依次递增) 3 个 Header 属性共同来控制
协商缓存由:
ETag(响应头)/If-None-Match(请求头):hash
- ETag 是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。 浏览器接收到 ETag 的值,会在下次请求时,将这个值作为 If-None-Match 这个字段的内容,并放到请求头中,然后发给服务器。 服务器接收到 If-None-Match 后,会跟服务器上该资源的 ETag 进行比对:
- 如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
- 否则返回304,告诉浏览器直接用本地缓存。
Last-Modified(响应头)/If-Modified-Since(请求头):
- 在浏览器第一次给服务器发送请求后,服务器会在响应头中加上 Last-Modified(最后修改时间) 这个字段。浏览器接收到后,会在下次请求时,将这个值作为 If-Modified-Since 这个字段的内容,并放到请求头中,然后发给服务器。服务器拿到请求头中的 If-Modified-Since 的字段后,其实会和这个服务器中该资源的最后修改时间对比:
- 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
- 否则返回304,告诉浏览器直接用本地缓存。
优先级:
强制缓存 > 协商缓存 在协商缓存中,Hash 值 > 上次修改时间
使用缓存的好处主要有以下几点:
- 减少了冗余的数据传输,节省了网费。
- 缓解了服务器的压力, 大大提高了网站的性能
- 加快了客户端加载网页的速度
Cookie 与 Session 的区别
二者都是用来跟踪浏览器用户身份的会话方式。
Cookie:
存在浏览器里,可以设置过期时间 每次访问服务器时,浏览器会自动在 header 中携带 cookie 如果浏览器禁用了 cookie,可以使用 URL 重写机制,将信息保存在 URL 里
Session:
存在服务端,由服务器维护,一段时间后 session 就失效了
本质上,session 还是通过 cookie 实现的。浏览器的 cookie 中只保存一个 sessionId,所有其他信息均保存在服务端,由 sessionId 标识
Session 失效,其实是服务器设置了失效时间。如果用户长时间不和服务器交互(比如 30 分钟),那么 session 就会被销毁;交互的话,就会刷新 session
HTTP/1.0、HTTP/1.1、HTTP/2.0
HTTP/1.0
- 在请求中新增了协议版本信息
- 引入了 HTTP 头的概念
- 在响应中新增了状态码
- 默认使用短连接:浏览器每请求一个静态资源,就建立一次连接,任务结束就中断连接
HTTP/1.1
- 默认支持长连接:在一个网页打开期间,所有网络请求都复用同一条已经建立的连接
- Pros:性能更好,节省频繁建立 TCP 连接、慢启动、关闭连接等的时间,整体耗时更短
- Cons:会占用服务器的资源
- 引入管线化(Pipelining):从前发送请求后需等待并收到响应,才能发送下一个请求,现在允许客户端同时并行发送多个请求
- Pros:在收到上一个请求的响应之前就可以发出下一个请求,能够节省请求到达服务器的时间,降低通信延迟
- Cons:服务器要遵循 HTTP/1.1 协议,必须按照客户端发送的请求顺序返回响应,可能发生队头阻塞(HOL blocking)——若上一个请求的响应迟迟没有处理完毕,则后面的响应都会被阻塞
HTTP/2.0
Header 压缩、服务端推送、多路复用
-
Header 压缩
HTTP/1.1 每次通信都会携带 Header 信息用于描述资源属性。但 headers 在一系列请求中常常是相似的。HTTP/2.0 中,对于 Header 中相同的数据,不会在每次通信中重新发送,而是采用追加或替换的方式。
具体实现上,HTTP/2.0 在客户端和服务端之间共同维护一个 Header 表,存储之前发送的 key-value 对。Header 表在 HTTP/2.0 的连接期间始终存在。
Header 压缩可以减少每次通信的数据量,提高传输速度。
-
服务端推送
服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确的请求。
服务端根据客户端的请求,提前推送额外的资源给客户端。比如在发送页面 HTML 时主动推送其它 CSS/JS 资源,而不用等到浏览器解析到相应位置,发起请求再响应。
服务端推送可以减轻数据传输的冗余步骤,同时加快页面响应速度,提升用户体验。
-
多路复用
-
二进制分帧:HTTP/1.x 使用文本格式传输数据。HTTP/2.0 在将所有传输信息分割为若干个帧,采用二进制格式进行编码。具体实现上,是在应用层(HTTP)和传输层(TCP)之间增加一个二进制分帧层。
-
多路复用: HTTP/1.x 有顺序和阻塞约束:
顺序:服务端必须按照客户端请求到来的顺序,串行返回数据 ; 即使 HTTP/1.1 允许通过同一个连接发起多个请求,也无法真正并行传输
阻塞:浏览器会限制每个域名下最多同时发起的 6 个连接,超过该数量的连接会被阻塞,以下是常见的优化方法:- 使用多个域名(比如 CDN)来提高浏览器的下载速度
- 将多个 JS 文件、CSS 文件等打包成一个文件,将多个小图片合并为雪碧图,减少 HTTP 请求数
HTTP/2.0 引入了多路复用,通过同一个连接发起多个请求,服务端可以并行地传输数据。基于二进制分帧层,HTTP/2.0 可以同时交错发送多个消息中的帧,接收端可以根据帧中的流标识符和顺序标识,重新组装数据。
-
HTTP Strict Transport Security(HSTS)
HSTS 的实现也很简单,通过 HTTPS 协议访问你站点的时候,在相应头中加上这样一段信息:
Strict-Transport-Security "max-age=63072000; includeSubdomains;"
Strict-Transport-Security 是 Header 字段名, 后面的 max-age 代表 HSTS 在客户端的生效时间。 includeSubdomains 表示对所有子域名生效。
用户的浏览器一旦得到了 HSTS 的信息,下次再访问站点的时候客户端浏览器就会强制使用 HTTPS。 无论你在地址栏里输入什么,都会以 HTTPS 访问。
DNS原理
整体流程:浏览器搜索自身的 DNS 缓存、搜索操作系统的 DNS 缓存、读取本地的 Host 文件和向本地 DNS 服务器进行查询等。
DNS 查询共有两类:递归查询和迭代查询。
- 递归查询是指,当 A 向 B 查询某个域名的 IP 地址时,如果 B 不知道被查询的域名的 IP 地址,那么 B 会替 A 向更上层的服务器发起查询,将查询结果返回 A。
- 迭代查询是指,当 A 向 B 查询某个域名的 IP 地址时,如果 B 不知道被查询的域名的 IP 地址,B 会告诉 A 下一步应该向哪个服务器查询,由 A 自己去查。
一般来说,主机(也就是我们的电脑)向本地域名服务器的查询是递归查询,而本地域名服务器向根域名服务器的查询是迭代查询。
- 根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”“net”“cn”等顶级域名服务器的 IP 地址。
- 顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址。
- 权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如 apple.com 权威域名服务器可以返回 www.apple.com 的 IP 地址。
从输入一个 URL 到页面加载完成的过程
- 每打开一个标签页,就创建了一个独立的浏览器渲染进程。用户在某个标签页输入 URL 并回车后,浏览器主进程会新开一个网络线程,发起 HTTP 请求
- 浏览器会进行 DNS 查询,将域名解析为 IP 地址
- 浏览器获得 IP 地址后,向服务器请求建立 TCP 连接
- 浏览器向服务器发起 HTTP 请求
- 服务器处理请求,返回 HTTP 响应
- 浏览器的渲染进程解析并绘制页面
- 如果遇到 JS/CSS/图片 等静态资源的引用链接,重复上述过程,向服务器请求这些资源
- 当我们再次发起GET请求,请求还未发出时,浏览器会首先检查 是否有缓存 ,如果 存在缓存 ,是否为强缓存,强缓存不需要发送请求到服务器,直接取浏览器本地缓存即可,如果不存在强缓存或者强缓存失效,则走协商缓存。
浏览器的渲染流程:
- 解析 HTML 文件,构建 DOM 树,同时下载 CSS 等静态资源
- CSS 文件下载完成后,解析 CSS 文件,形成 CSSOM 树
- DOM 与 CSSOM 合并得到渲染树 Render Tree
- 计算渲染树中各个元素的尺寸、位置,这个过程称为回流 Reflow
- 浏览器将各个图层的信息发送给 GPU,GPU 绘制页面

京公网安备 11010502036488号