计算机网络知识点归纳


网络分层模型


介绍一下 OSI 七层协议,各层协议都有哪些?

答:

  • OSI 参考模型共有 7 层,从上到下分别是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
    • 应用层的协议有: HTTP、HTTPS
    • 传输层的协议有:TCP 和 UDP
    • 网络层的协议有:IP、ICMP、ARP
  • 我认为,网络分层的好处是:对各个层之间进行了解耦,层一层之间不会产生关联性,比如:我们应用层的 HTTP 协议,从 HTTP1.1 升级到 HTTP2.0 的时候,并不会对传输层、网络层等有影响,或者网络层的 IPv4 协议升级为 IPv6 协议的时候,也不会影响应用层、传输层
  • 不过,OSI 参考模型只是理论模型,实际上因特网中的网络模型是使用了 TCP/IP 网络模型,它对 OSI 参考模型做了简化,把 应用层、表示层、会话层 统一成了 应用层,数据链路层 和 物理层 统一成了 网络接口层

补充:

OSI模型 TCP/IP模型

  • OSI 的 7 层模型从上到下依次为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
  • 应用层:负责直接与 软件应用程序 交互以提供所需的通信功能,并且它 与最终用户最接近
    • 应用层的功能:通常包括 验证通信伙伴 和 资源的可用性 以支持任何数据传输。该层还定义了用于最终应用程序的协议,例如:域名系统(DNS)、文件传输协议(FTP)、超文本传输协议(HTTP)、Internet 消息访问协议(IMAP)、邮局协议(POP)、简单邮件传输协议(SMTP)、简单网络管理协议(SNMP)和 Telnet(终端仿真)
  • 表示层:表示层提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另个系统的应用层识别,如:数据转换,压缩和加密,解密
    • 表示层可以 处理任何所需的数据格式或代码转换
    • 例如:将扩展 二进制编码 的 十进制交换码(EBCDIC)编码的文本文件 转换为 美国信息交换标准码(ASCII)编码的文本文件
    • 表示层也 可用于数据压缩和加密
    • 例如:视频呼叫将在传输过程中被压缩。以便可以更快地传输,并且数据将在接收方恢复。对于具有较高安全性要求的数据(例如:包含你的密码的短信),将在此层进行加密
  • 会话层:会话层控制计算机之间的对话(连接)它建立,管理,维护并最终终止本地和远程应用程序之间的连接
    • 会话层软件 还 处理 身份验证 和 授权功能。会话层通常在使用远程过程调用的应用程序环境中明确实现
  • 传输层:负责两个设备间的 端 到 端 通信
    • 包括:从会话层提取数据,将数据分解为多个数据,然后再发送到网络层
    • 传输层还负责进行 流量控制 和 错误控制。流量控制 用于 确定最佳传输速度,避免发送方发送速率过快导致接收方接收不过来的情况。传输层还会确保接收数据的完整性(如果不完整,则请求重新传输)来对接收端进行错误控制。传输层包含 TCP 和 UDP 协议
  • 网络层:网络层通过 逻辑寻址 和 交换功能 处理 数据包路由
    • 这一层:实现 不同网络 之间的 数据传输。它进一步将网段或数据报分解成更小的数据包,并使用 IP 地址找到通往最终目的地的最佳路由。这一过程被称为 路由选择
    • 网络是可以连接许多 节点 的介质。每个节点都有一个地址。当一个节点需要将消息传输到其他节点时,它仅能提供 消息的内容 和 目标节点的地址,则网络将找到将消息传递到目标节点的方法,并可能通过其他节点进行路由。如果消息太长,网络可能会在一个节点上将其拆分为多个段,分别发送它们,然后在另一节点上重新组合片段
  • 数据链路层:数据链路层提供 节点 到 节点 的传输,即:两个直接连接的节点之间的链接
    • 这一层允许在 同一网络 的 设备 之间传输数据。数据包 被分解成 帧,这些帧被限制在 局域网 内
    • 它以 帧 的形式处理 数据的打包 和 拆包。它定义了在两个物理连接的设备之间建立和终止连接的协议,例如:点对点协议(PPP)
    • 数据链路层通常分为两个子层:媒体访问控制(MAC)层和 逻辑链路控制(LLC)层。MAC 层负责控制网络中的设备如何访问媒体以及允许传输数据。LLC 层负责标识和封装网络层协议,并控制错误检查和帧同步
  • 物理层:物理层定义了数据连接的物理规格
    • 例如:连接器的插针布局,电缆的工作电压,光纤电缆规格以及无线设备的频率。它负责物理介质中非结构化原始数据的发送和接收

详细链接:面试官:我们为什么需要 7 层 OSI 网络模型?、什么是 OSI 模型? | Cloudflare


TCP/IP 网络模型有哪几层?

答:

  • TCP/IP 网络模型主要有 四 层,从上到下分别是:应用层、传输层、网络层、网络接口层
  • 应用层:负责为 应用软件 提供 网络服务
    • 例如:HTTP、HTTPS、DNS等协议
  • 传输层:负责为 应用程序层 提供 数据传输服务
    • 传输层协议 主要有 TCP 和 UDP
      • TCP是 可靠 传输协议
      • UDP 是 不可靠 的传输协议
  • 网络层:负责主机 寻址,打包 和 路由 功能
    • 网络层的核心协议是:IP、ARP、ICMP 等协议
      • IP 协议负责寻址和路由
      • ARP 协议负责获取 MAC 地址
      • ICMP 负责提供诊断功能并报告错误
  • 网络接口层:负责为 网络层提供「链路级别」传输的服务,负责 在 以太网、WiFi 这样的底层网络上发送原始数据包
    • 工作在 网卡 这个层次,使用 MAC 地址来标识网络上的设备

补充:

TCP/IP网络模型

  • TCP/IP 网络模型有两种说法, 有的说 五 层 TCP/IP 网络模型,有的说 四 层 TCP/IP 网络模型

    • 四层 TCP/IP 网络模型是:应用层、传输层、网络层、网络接口层
    • 五层 TCP/IP 网络模型是:应用层、传输层、网络层、数据链路层、物理层
  • TCP/IP 网络通常是由上到下分成 4 层,分别是:应用层,传输层,网络层 和 网络接口层

  • 应用层:TCP/IP 模型的应用程序层使应用程序能够访问其他层的服务,并定义了应用程序用来交换数据的协议

    • 最熟悉的应用层协议包括:HTTP、FTP、SMTP、Telnet、DNS、SNMP 和 路由信息协议(RIP)
  • 传输层:传输层负责 为 应用程序层 提供 会话 和 数据通信服务

    传输层

    • 该层的核心协议是 TCP 和 UDP
      • TCP 提供 一对一,面向连接 的 可靠通信服务。它负责对发送的数据包进行排序和确认,并恢复传输中丢失的数据包
      • UDP 提供 一对一 或 一对多 的 无连接,不可靠 的通信服务。当要传输的数据量较小时(例如,该数据可以放入单个数据包中),通常使用 UDP
  • 网络层:网络层 负责 主机寻址,打包 和 路由功能

    网络层

    • 网络层负责 将 数据 从 一个设备 传输到 另一个设备
    • 网络层的核心协议:IP、地址解析协议(ARP)、Internet 控制消息协议(ICMP)和 Internet 组管理协议(IGMP)
      • IP 是可路由协议,负责 IP 寻址,路由以及数据包的分段和重组
        • 将 IP 地址分成两种意义:
          • 一个是 网络号,负责标识该 IP 地址是属于哪个「子网」的
            • IP 地址与 子网掩码 按位 与 运算
          • 一个是 主机号,负责标识同一「子网」下的不同主机
            • IP 地址与 子网掩码取反后 按位 与 运算
      • ARP 负责发现网络访问层地址,例如:与给定 Internet 层访问关联的硬件地址
      • 由于 IP 数据包传递失败,ICMP 负责提供诊断功能并报告错误
      • IGMP 负责 IP 多播组的管理。IP 在此层中将标头添加到数据包中,称为 IP 地址。现在既有 IPv4 (32位)地址又有 IPv6 (128位)地址
  • 网络接口层:网络接口层 负责将 TCP/IP 数据包放在网络介质上,并从网络介质上接收 TCP/IP 数据包

    • TCP/IP 被设计为 独立于网络访问方法,帧格式 和 介质。换句话说,它独立于任何特定的网络技术。这样,TCP/IP 可以用于连接不同的网络类型,例如:以太网,令牌环,X.25,帧中继和异步传输模式(ATM)

TCP/IP的封装格式

详细链接:2.1 TCP/IP 网络模型有哪几层? | 小林coding


IP 协议和 TCP 协议属于哪一层?

答:

IP 协议属于 网络层,TCP 协议属于 传输层


网络为什么要分层?

答:

  • 分层的目的是 为了降低耦合,各层相互独立之后,上层可以不关心下层的实现,只关心下层提供的接口服务,有利于排查网络问题,能更精细定位问题所在哪一层
  • 分层之后层与层之间不会产生关联性,不会因为某个层的改动,影响了其他层
    • 比如:应用层的 HTTP 协议,从 HTTP1.1 升级到 HTTP2.0 的时候,并不会对 传输层、网络层 等有影响,或者网络层的 IPv4 协议升级为 IPv6 协议的时候,也不会影响 应用层、传输层

补充:

  • 分层的好处:
    1. 各层之间是 独立的
      • 某一层 并不需要知道它 下一层 是如何实现的,而仅仅需要知道该层通过层间的接口所提供的服务。由于每一层只实现一种相对独立的功能,因而可以将一个难以处理的复杂问题分解为若干个较容易处理的更小问题,这样,整个问题的复杂度就下降了
    2. 灵活性好
      • 当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或以下各层均不受影响此外,对某一层提供的服务还可以进行修改。当某层提供的服务不再需要时,甚至可以将这层取消

键入网址场景问题


输入网址后,期间发生了什么?

答:

在浏览器输入网址后:

  1. 浏览器会先解析 URL,解析出 域名、资源路径、端口 等信息,然后构造 HTTP 请求报文

    URL组成

  2. 接着进行 域名 解析,将 域名解析 为 IP 地址,会先查 系统缓存 是否 域名信息,如果有就返回 IP 地址,没有就会查看本地系统 host 文件有没有域名信息,如果有就返回 IP 地址,如果没有就去查本地 DNS 服务器,如果本地 DNS 服务器缓存中有域名信息,就返回 IP 地址,否则本地 DNS 服务器分别去 根域名服务器 → 顶级域名服务器 → 权威域名服务器询问,最后拿着返回的 IP 交给浏览器

    DNS域名解析器关系图

  3. 由于 HTTP 是基于 TCP 传输的,所以 在发送 HTTP 请求前,要进行 三次握手,在客户端发送第一次握手的时候,TCP 头部会填上 SYN 标记位,同时填上 目标端口 和 源端口 的信息。源端口 是 浏览器随机生成的,目标端口要看是 HTTP 还是 HTTPS,如果是 HTTP 默认目标端口是 80,如果是 HTTPS 默认是 443

  4. 然后到 网络层,会加上 IP 头,同时填上 目标 IP 地址 和 源 IP 地址

  5. 然后到 数据链路层,会通过 ARP 协议,获取路由器的 MAC 地址,然后会加上 MAC 头,填上 目标MAC地址 和 源 MAC 地址

  6. 然后到 物理层 之后,直接把 数据包,转发给 路由器,路由器再通过下一跳,最终找到 目标服务器,然后目标服务器收到客户的 SYN 报文后,会响应第二次握手

  7. 当双方都 完成 三次握手 后,如果是 HTTP 协议,客户端就会将 HTTP 请求就会发送给目标服务器;如果是 HTTPS 协议,客户端 还要和 服务端 进行 TLS 四次握手之后,客户端才会将 HTTP 报文发送给目标服务器

  8. 目标服务器收到 HTTP 请求消息后,就返回 HTTP 响应消息,浏览器会对响应消息进行解析渲染,呈现给用户

补充:

关键要讲出输入网址后涉及的每一个网络协议的工作原理和作用:

  • HTTP/HTTPS 协议 → DNS 协议 → TCP 协议 → IP协议 → ARP 协议

输入网址后的流程图

详细链接:2.2 键入网址到网页显示,期间发生了什么? | 小林coding


DNS 是如何解析的?属于哪一层的协议?

答:

  • DNS 属于 应用层 的协议
    • 客户端在进行 DNS 解析之前,会先查看 浏览器 和 操作系统 是否有缓存域名对应的 IP 地址,没有就会查看本地系统 host 文件有没有域名信息,如果有就返回 IP 地址
    • 如果没有就会向本地 DNS 服务器发出查询请求,如果没有接着本地 DNS 向 根 DNS 发送查询请求,根 DNS 服务器收到请求后会返回顶级域名服务器的 IP 地址,然后本地 DNS 服务器再向顶级域名服务器发出查询请求,顶级 DNS 服务器收到请求后会返回权威域名服务器的 IP 地址,然后本地 DNS 服务器再向 权威域名服务器 发出查询请求,权威域名服务器 收到请求后,就会返回域名对应的 IP 地址了,最后本地 DNS 服务器返回查询结果给客户端,同时本地域名服务器把返回的结果保存到缓存,以备下一次使用。客户端通过这个 IP 地址就可以访问目标 Web 服务器了。到这里,DNS 查询的整个过程就结束了

补充:

具体流程

详细链接:公网域名解析_云解析服务 DNS_华为云


DNS域名解析使用的什么协议?

答:

  • 在 DNS 中,域名解析 请求 和 响应 都是基于 UDP 进行传输的
  • UDP 是一种 无连接 的 传输层协议,它提供了一种简单的传输机制,适用于对 实时性要求较高 的应用场景。DNS 使用 UDP 协议进行域名解析是因为 域名解析 通常是 短小而频繁 的请求,UDP 的无连接特性可以减少建立和断开连接的开销,并提高解析的效率(UDP 协议以及 UDP相较于 TCP的优点)
  • UDP 对于 TCP 的缺点是没办法保证数据的可靠传输,针对这个缺陷,可以在应用层实现一个超时重传机制,如果域名解析请求在一定时间内没收到响应,那么就重发域名解析请求(UDP 不保证可靠性的缺点)

详细链接:DNS 协议是什么?完整查询过程?为什么选择使用 UDP 协议发起 DNS 查询?> 你可能了解 DNS 协议是什么?那 - 掘金


输入域名如何知道端口的?

答:

HTTP 默认端口是 80,HTTPS 默认端口是 443,如果用户指定了端口,比如:域名:8080,这时候就会使用8080 作为目标端口

补充:

  • http://baidu.com/,默认端口是 80
  • https://baidu.com/,默认端口是 443
  • http://baidu.com:8080/,指定的端口是 8080

详细链接:[11 你能写出正确的网址吗?](https://learn.lianglianglee.com/专栏/透视HTTP协议/11 你能写出正确的网址吗?.md)


客户端向服务端的 IP 地址发送数据,服务端如何确定应该把数据传递给谁?

答:

服务端的应用会监听端口,协议栈会通过端口来区分不同应用的数据

补充:

每个传输层协议(如:TCP 和 UDP)都使用 端口号 来标识不同的应用程序或服务,服务端 通过 监听 特定的端口号来接收来自客户端的数据


现在很多网站都要求使用 https,假设我们输入一个 http 网址,网站是如何实现由 http 跳转到 https 的?

答:

  • 服务器网关收到 http 请求后,给客户端一个 http 响应,状态码为 301(永久重定向)
  • 浏览器收到 重定向 响应后,自动向服务器发起一个新的 HTTPS 请求(默认端口 443)

补充:

网站实现由 HTTP 跳转到 HTTPS 的过程通常涉及 服务器端的配置,以确保用户访问的是 加密 的连接。以下是 nginx 服务器端配置方法,可以在虚拟主机的配置文件中添加以下代码来实现重定向:

1
2
3
4
5
server {
listen 80;
server_name example.com;
return 301 https://$host$request uri;
}

网络传输场景问题


如果浏览器没有显示页面有哪些原因?

答:

最直接的办法就是 抓包,排查的思路大概有:

  1. 先确定是 服务端 的问题,还是 客户端 的问题
    • 先在 客户端 确认浏览器是否可以访问其他网站,如果不可以,说明客户端网络自身的问题,然后检查 客户端 网络配置(连接 wifi 正不正常,有没有插网线)
    • 如果可以正常其他网页,说明 客户端 网络是可以正常上网的
  2. 如果 客户端 网络没问题,就抓包确认 DNS 是否解析出了 IP 地址,如果没有解析出来,说明域名写错了,如果解析出了 IP 地址,抓包确认有没有和服务端建立三次握手:
    • 如果没有成功建立三次握手,需要在服务端通过 ps 确认 server 进程是否启动了,以及通过 netstate 命令确认是否监听了端口
    • 如果能成功建立三次握手,并且发出了 HTTP 请求,但是就是没有显示页面,可以查看服务端返回的响应码:
      • 如果是 404 错误码,检查输入的 url 是否正确
      • 如果是 500,说明服务器此时有问题,这时候就需要去服务器排查日志了
      • 如果是 200,可以在浏览器按 F12 输出前端控制台,看看前端代码有问题导致浏览器没有渲染出页面
  3. 如果 客户端 网络是正常的,但是访问速度很慢,导致很久才显示出来。可以通过 ping 去确认网络延迟是否正常,如果耗时很严重,可以排查服务器的流量是不是很大,导致超过了带宽上限,产生了丢包的问题。如果网络是正常的,可能要排查接口为什么处理这么久,这里有可能是慢 sql 导致的

总之就 是一层一层有没有插网线,网络配置是否正确、DNS 有没有解析出 IP 地址、TCP 有没有三次握手、HTTP 返回的响应码是什么

详细链接:字节一面:网站显示不出来,怎么排查?


服务器ping不通但是http能请求成功,会出现这种情况吗?

答:

  • 会的
  • 因为 ping 和 http 使用的协议是不一样的,ping 是基于网络层的 ICMP 协议,而 http 是基于传输层的 TCP 协议的,有可能服务器的防火墙禁止 ICMP 协议,但是 TCP 协议没有禁止,就会出现服务器 ping 不通,但是 http 能请求现象

补充:

  • 主要是 ping 和 http 底层的协议区别

详细链接:5.2 ping 的工作原理 | 小林coding


客户端 TCP 连接一个不存在的 IP 地址的服务端会发生什么?(cold)

答:

  • 分情况讨论:
    1. 如果访问的 IP 地址是局域网内的,客户端的内核在发 ARP 请求的时候,广播询问这个目标 IP 地址是谁的,由于网络中不存在该目标 IP 地址,所以没有设备应答客户端的 ARP 请求,这时候就会卡在 ARP 协议,客户端的 SYN 报文是发送不出去的
    2. 如果访问的 IP 地址不是局域网的,客户端会先将 SYN 报文发给路由器,然后路由器会继续转发,由于目标 IP 地址是不存在的,该 SYN 报文会在网络中消亡,因此客户端是不会收到对 SYN 报文的确认报文的,接着客户端会触发超时重传,重传 SYN 报文,直到重传的次数达到最大次数后,客户端的连接就会被释放

详细链接:字节面试:连接一个不存在的 IP 地址,会发生什么?


客户端 TCP 连接一个 IP 地址存在但是端口不存在的服务端会发生什么?(cold)

答:

端口不存在的话,代表服务端没有监听这个端口,服务端在收到客户端的 SYN 报文后,服务端会回 RST 报文,客户端收到 RST 报文后,会断开连接

补充:

举例

  • 如果客户端访问了没有被服务端监听的端口的话,服务端会回 RST 报文

详细链接:4.19 服务端没有 listen,客户端发起连接建立,会发生什么? | 小林coding


客户端 UDP 发送一个 IP 地址存在但是端口不存在报文会发生什么?(cold)

答:

服务端会回 ICMP 报文,报告端口不可达

补充:

UDP 没有 RST 报文,所以如果端口不存在,这时候会在网络层通过 ICMP 协议,报告端口不可达的消息给客户端

举例

详细链接:关于UDP接收icmp端口不可达(port unreachable)_icmp port unreachable-CSDN博客


HTTP


HTTP 协议的特点是什么?

答:

  • HTTP 具有简单、灵活可扩展、无状态等特点,是一种广泛应用于 Web 通信的协议
    1. 基于文本:HTTP 的消息是以 文本形式 传输,易于阅读和调试
    2. 可扩展性:HTTP 协议本身不限制数据的内容和格式,可以通过 扩展头部、方法 等来支持新的功能
    3. 灵活性:HTTP 支持不同的数据格式(如:HTML、JSON、XML 等),适用于多种应用场景
    4. 请求应答模式:HTTP 协议使用的是 请求 - 应答 通信模式,请求方先发起连接和请求,是主动的,而应答方只有在收到请求后才能答复,是被动的,如果没有请求时不会有任何动作
    5. 无状态:HTTP 每个请求之间相互独立,服务器不会保留之前请求的状态信息,需要通过其他手段(如:Cookies、Session)来维护状态

补充:

  • HTTP 是 灵活可扩展 的,可以任意添加头字段实现任意功能
  • HTTP 是可靠传输协议,基于 TCP/IP 协议 “尽量” 保证数据的送达
  • HTTP 是应用层协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据
  • HTTP 使用了 请求 - 应答 模式,客户端主动发起请求,服务器被动回复请求
  • HTTP 本质上是无状态的,每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。

详细链接:[13 HTTP有哪些特点?](https://learn.lianglianglee.com/专栏/透视HTTP协议/13 HTTP有哪些特点?.md)


HTTP 报文格式?怎么分割的?

答:

  • HTTP 报文格式分为 请求行、请求头、请求体 三个部分:
    • 请求行 是 请求或响应的基本信息,比如:请求方法、URL、HTTP 版本信息
    • 请求头 是 用 key-value 形式更详细地说明报文,比如:Host 字段、Connection 字段、Content-Length 字段
    • 请求体 是 实际传输的数据,比如:文本数据、图片数据
  • 请求行 和 请求头 是通过 \r\n 分割的,请求头 和 请求体 之间是通过 空白行 分割的,也就是 两个连续的\r\n

补充:

  • HTTP 报文格式分为 请求行、请求头、请求体 三个部分
    • 请求行的内容是 HTTP 方法、URL、HTTP 版本号,请求行里的字段之间是通过 空格 分割,请求行 和 请求头 是通过 \r\n 分割的
    • 请求头 的 内容 是 多个键值对字段的集合,键 和 值 通过 冒号 分割,每个字段之间通过 \r\n 分割
    • 请求体 的内容是 实体数据,请求头 和 请求体 之间是通过 空白行 分割的,即:两个连续的\r\n(回车符 + 换行符)

HTTP报文格式

详细链接:[09 HTTP报文是什么样子的?](https://learn.lianglianglee.com/专栏/透视HTTP协议/09 HTTP报文是什么样子的?.md)


HTTP 默认的端口是什么?

答:

80 端口

补充:

端口 是 TCP 的概念,针对 HTTP 协议,服务端默认是监听 80 端口,针对 HTTPS 协议,服务端默认是监听 443 端口

详细链接:HTTP、HTTPS常用的默认端口号 - 景寓6号 - 博客园


HTTP 有什么方法?

答:

  • 我了解到 HTTP 方法的有 GET、POST、PUT、HEAD、DELETE 这些方法,其中:
    • GET 方法是用来 请求从服务器获取资源的
    • HEAD 方法和 GET 方法类似,也是请求从服务器获取资源,但与 GET 请求不同的是,服务器不会返回请求的实体数据,只会传回响应头,也就是获取的是资源的 “元信息”
    • POST 方法是 用来向服务端提交数据,数据就放在报文的 body 里
    • PUT 方法和 POST 类似,也可以向服务器提交数据,区别在于 POST 是 “新增数据”,PUT 是 “更新数据”
    • DELETE 方法是用来 删除资源
  • 在项目开发中,用的比较多是 GET 和 POST 请求

补充:

目前 HTTP/1.1规定的八种方法,单词必须是 大写 的形式

HTTP/1.1 规定的八种方法

详细链接:[10 应该如何理解请求方法?](https://learn.lianglianglee.com/专栏/透视HTTP协议/10 应该如何理解请求方法?.md)


分析一下哪些 HTTP 方法是安全或者幂等的?

答:

  • GET 和 HEAD 方法是 安全且幂等 的,因为它们是 只读 操作,只要开发者遵循规范要求的去处理请求,无论 GET 和 HEAD 操作多少次,服务器上的数据都是安全的
  • POST / PUT / DELETE 这些方法都会 增上改服务器上的资源,所以是 不安全 的
  • DELETE 和 PUT 方法是 幂等 的,因为 DELETE 是 删除资源,多次删除,效果都是资源不存在,所以也是 幂等 的,另一个 PUT 是 更新数据,多次更新数据,结果都一样,所以是 幂等 的
  • 但是 POST 是不幂等的,因为多次 POST 请求,会创建多个资源,所以 不是幂等 的

补充:

  • 在 HTTP 协议里:
    • 所谓的 “安全” 是指:请求方法不会 “破坏” 服务器上的资源,即:不会对服务器上的资源造成实质的修改
    • 所谓的 “幂等” 实际上是一个数学用语,被借用到了 HTTP 协议里,意思是:多次执行相同的操作,结果也都是相同的,即:多次 “幂” 后结果 “相等”
  • 分类:
    • 安全的方法:GET / HEAD
    • 不安全的方法:POST / DELETE / PUT
    • 幂等的方法:GET / HEAD / DELETE / PUT
    • 不幂等的方法:POST

GET 和 POST 请求的区别?

答:

  • GET 请求是 从服务器获取资源,POST 请求是 向服务器提交数据
  • GET 方法是 只读 操作,所以是 安全且幂等 的,而 POST 方法会修改服务器上的资源,并且多次 POST 请求,会创建多个资源,所以 不是安全,也不是幂等 的
  • GET 请求的请求参数放在 URL 中的查询字符串中,浏览器对 URL 长度限制,所以 GET 请求的请求参数会有长度限制,而 POST 请求的请求参数是放在请求体中,POST 请求的请求参数长度没有限制

补充:

从几个角度分析:

  1. 两个请求的语义上的区别
  2. 两个请求的是否是安全且幂等的?
  3. 请求参数的区别

GET 请求一定是安全且幂等的吗?

答:

不一定,要看实际的 GET 请求,如果 开发者遵循了规范去处理请求,也就是 GET 请求的实现是获取资源,那么就是安全且幂等的,但是 如果开发者处理 GET 请求的方式是 新增数据,这时候 GET 请求就 不是安全且幂等的


HTTP 有什么状态码?

答:

HTTP 状态共有 5 类:

  • 数字 1 开头的状态码:表示目前是 协议处理的中间状态,还需要后续操作,比如:客户端请求服务端从 HTTP 切换为 WebSocket 通信的时候,服务端如果同意切换,就会回 101 状态码
  • 数字 2 开头的状态码:表示 服务器收到并成功处理了客户端的请求,比如:200 状态码是代表 服务端 成功响应了 客户端 的请求
  • 数字 3 开头的状态码:表示 服务端的资源发生了变动,需要进行 重定向 了,比如:301 是代表永久重定向、302 代表临时重定向
  • 数字 4 开头的状态码:是 客户端错误,表示客户端发送的请求报文有误,服务器无法处理,比如:404 状态码表示资源在本服务器上未找到
  • 数字 5 开头的状态码:是 服务端错误,服务器在处理时内部发生了错误,比如:502 状态码是 nginx 服务器作为代理时返回的错误码,表示 nginx 服务器自身工作正常,但是访问后端服务器时发生了错误,具体的错误需要去排查后端服务器

补充:

  • 100 类状态码属于 提示信息,是协议处理中的一种中间状态,实际用到的比较少
    • “101 Switching Protocols”:请求者已要求服务器切换协议,服务器已确认并准备切换
      • 它的意思是客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如:WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了
  • 200 类状态码表示 服务器成功处理了客户端的请求
    • “200 OK”是 最常见的成功状态码:表示一切正常,服务器如客户端所期望的那样返回了处理结果,如果是非 HEAD 请求,通常在响应头后都会有 body 数据
    • “204 No Content” 是 另一个很常见的成功状态码,它的含义与 “200 OK” 基本相同,但响应头后没有 body 数据。所以对于 Web 服务器来说,正确地区分 200 和 204 是很必要的
    • “206 Partial Content” 是 HTTP 分块下载或断点续传的基础,在客户端发送 “ 范围请求 ”、要求获取资源的部分数据时出现,它与 200 一样,也是服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分
  • 300 类状态码表示 客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向
    • “ 301 Moved Permanently ”:代表 永久性的重定向,值得注意的是,这种重定向跳转,从严格意义来讲不是服务器跳转,而是客户端跳转的。这个 “ 跳 ” 的动作是服务器是通过回传状态码 301 来下达给客户端的,让客户端完成跳转
    • “ 302 Found ”:代表 临时跳转。例如:URL 地址 A 可以向 URL 地址 B 上跳转,但这并不是永久性的,在经过一段时间后,URL 地址 A 还可能向 URL 地址 C 上跳转
    • “ 304 Not Modified ”:服务器通过返回状态码 304 可以告诉客户端请求资源成功,但是这个资源不是由服务器提供返回给客户端的,而是客户端本地浏览器缓存中就有的这个资源,因为可以从缓存中获取这个资源,从而节省传输的开销
  • 400 类状态码表示 客户端发送的报文有误,服务器无法处理
    • “ 400 Bad Request ”:表示 请求报文有错误,但具体是数据格式错误、缺少请求头还是 URI 超长它没有明确说,只是一个笼统的错误,客户端看到 400 只会是 “ 一头雾水 ”、“不知所措”
    • “ 403 Forbidden ”:代表 请求的服务器资源权限不够,也就是没有权限去访问服务器的资源,或者请求的 IP 地址被封掉了
    • “ 404 Not Found ”:代表 服务器上没有该资源,或者说服务器找不到客户端请求的资源,是最常见的请求错误码
  • 500 类状态码表示 客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码
    • “ 500 Internal Server Error ”:代表 服务器程序错误,也就是说请求的网页程序本身报错了。在服务器端的网页程序出错。由于现在的浏览器都会对状态码 500 做一定的处理,所以在一般情况下会返回一个定制的错误页面
    • “ 501 Not Implemented ”:服务器不具备完成请求的功能。 例如:服务器无法识别请求方法时可能会返回此代码。
    • “ 502 Bad Gateway ”:通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误
    • “ 503 Service Unavailable ”:表示服务器当前很忙,暂时无法响应客户端。我们上网时有时候遇到的 “网络服务正忙,请稍后重试” 的提示信息就是状态码 503
    • “ 504 Gateway Timeout ”:服务器作为网关或代理,但是没有及时从上游服务器收到请求

HTTP状态码五大类

详细链接:[12 响应状态码该怎么用?](https://learn.lianglianglee.com/专栏/透视HTTP协议/12 响应状态码该怎么用?.md)


什么情况下会出现502错误码呢?

答:

如果客户端访问服务器是通过 Nginx 来反向代理到应用服务器,那么如果应用服务器出现了故障,导致Nginx 无法从应用服务器获取到响应,这时候 Nginx 就会返回 502 错误码给客户端

补充:

  • 502 (Bad Gateway)状态代码表示服务器在充当网关或代理时,在尝试满足请求时从它访问的入站服务器接收到无效响应
  • 简单理解就是,502 其实是由 网关代理(Nginx)发出的,是因为 网关代理把客户端的请求转发给了服务端,但服务端却发出了无效响应,而这里的无效响应,一般是指 TCP 的 RST 报文或四次挥手的 FIN 报文
    • 屏蔽掉具体有哪些服务器的代理方式 就是所谓的 反向代理
    • 异常情况下,收发双方都不一定正常,连四次挥手这件事本身都可能做不到,所以就需要一个机制去强行关闭连接:RST 一般用来异常地关闭一个连接,它是TCP包头中的一个标志位,在收到置这个标志位的数据包后,连接就会被关闭,此时接收到 RST 的一方,在应用层会看到一个 connection reset 或 connection refused 的报错

FIN与Errors502

RST与Errors502

详细链接:502问题怎么排查?你学会了吗?-502问题怎么解决


有个服务出现了504,你觉得这个服务是出了什么问题?

答:

504是 网关超时错误,通常是 Nginx 将请求代理到后端应用时,后端应用没有在规定的时间返回数据,需要开发检查下应用那块有什么耗时的操作,比如:是否出现了 sql 慢查询,接口是否发生死循环、死锁 等问题,然后后端服务器系统负载高不高

链接:面试又跪了,504 错误码是什么问题?


重定向是哪一类状态码?临时重定向和永久重定向有什么区别?

答:

  • 重定向 是数字 3 开头的状态码
    • 客户端收到 301 状态码后,会记忆重定向后的 URL 地址,这样下一次访 301 状态码是代表永久重定向,问的时候,不需要访问旧 URL,直接跳转到新 URL 访问
    • 302 状态码代表 临时重定向,客户端收到 302 状态码后,不会记忆重定向后的 URL 地址,下一次访问的时候,还需要访问旧的 URL,再跳转访问新的 URL

补充:

  • 301 永久重定向,浏览器会记住
    • 假如:当你访问 a.com 时,永久重定向到了 b.com;那么下一次访问 a.com 时浏览器会直接跳转到 b.com 不会再请求 a.com
  • 302 临时重定向,浏览器不会记忆
    • 假如:加入当你访问 a.com 时 临时重定向到了 b.com;那么下一次当你请求 a.com 时,浏览器还会先请求 a.com ,然后再重定向到 b.com

详细链接:重定向的理解301,302 - 知乎


HTTP 是长连接还是短连接?

答:

HTTP 1.0 虽然支持长连接,但是 默认的连接行为是 短链接,从 HTTP1.1 版本之后,都是 默认长连接了

补充:

在 HTTP 1.0 中默认是关闭的,如果浏览器要开启 Keep-Alive,它必须在请求的包头中添加:

1
Connection:Keep-Alive

然后当服务器收到请求,作出回应的时候,它也添加一个头在响应中:

1
Connection: Keep-Alive

这样做,连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个连接。这一直继续到客户端或服务器端提出断开连接
从 HTTP 1.1 开始, 就默认是开启了 Keep-Alive,如果要关闭 Keep-Alive,需要在 HTTP 请求的包头里添
加:

1
Connection:close

现在大多数浏览器都默认是使用 HTTP/1.1,所以 Keep-Alive 都是默认打开的。一旦客户端和服务端达成协议,那么长连接就建立好了,HTTP 长连接的优势是可以减少了 TCP 连接资源的开销

详细链接:4.15 TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗? | 小林coding


HTTP 长连接和短连接的区别?

答:

  • 短连接:每次通信请求都需要建立新的连接,请求完成后立即关闭连接。这样每次请求都需要建立连接和释放连接,会增加通信开销和延迟
  • 长连接:在通信过程中保持连接的持续性,多次请求可以共享同一个连接。在长连接中,客户端和服务器建立连接后可以进行多次请求和响应,减少了连接建立和释放的开销,提高了通信效率

补充:

短连接:每次通信请求都需要建立新的连接,请求完成后立即关闭连接,下次请求还需要重新建立 TCP 连
接

短链接

长连接:在通信过程中保持连接的持续性,多次请求可以共享同一个 TCP 连接

长连接


HTTP 长连接有什么好处?

答:

长连接 可以在一次 TCP 连接中可以发送和响应多个 HTTP 请求,可以减少了 TCP 连接资源创建和断开的开销

补充:

  • 短连接:在一次 TCP 连接中只能发送和响应一个 HTTP 请求,即:建立TCP → 请求资源 → 响应资源 → 释放连接
  • 长连接:在一次 TCP 连接中可以发送和响应多个 HTTP 请求,即:建立TCP → 请求资源 → 响应资源 → 请求资源 → 响应资源 → 请求资源 → 响应资源 → 请求资源 → 响应资源 → … → 释放连接

HTTP/1.0 和 HTTP/1.1 的区别?

答:

  • 长连接:HTTP/1.1 默认的连接行为是 长连接,而 HTTP/1.0 虽然也支持 长连接,但是默认是使用 短连接
  • 请求管道化:HTTP/1.1 支持 请求管道传输(pipline)的方式,HTTP/1.0 不支持这个模式,HTTP/1.0 请求和响应必须是串行的,当一个请求和它响应完成之后,才能发送下一个请求,而 HTTP/1.1 由于支持管道传输方式,因此可以并发发送 HTTP 请求,能够提高 HTTP 请求的效率,但是 HTTP 响应还是得按顺序响应,只有 HTTP/2.0 实现了 HTTP 请求和响应的并发传输的能力
  • host 字段:通过 host 头部字段,一个物理服务器可以承载多个域名或站点
    • HTTP/1.0 没有 host 字段,HTTP/1.1 新增了 host 字段

补充:

HTTP/1.0 和 HTTP/1.1 两者的主要区别体现在:

  • 长连接:在 HTTP/1.0 中,默认使用的是短连接,也就是每次请求都要重新建立一次连接。HTTP 是基于TCP/IP 协议的,每一次建立或者断开连接,都需要三次握手四次挥手的开销,如果每次请求都要这样的话,开销会比较大,因此最好能维持一个长连接,可以用长连接来发多个请求。HTTP 1.1 起,默认使用长连接 connection:keep-alive

  • 请求管道化:HTTP 1.1 支持请求管道化,即:在一个持久连接上可以同时发送多个请求,而 HTTP 1.0 不支持请求管道化,HTTP/1.0 请求和响应必须是串行的,当一个请求和它响应完成之后,才能发送下一个请求,而 HTTP/1.1 由于支持管道传输方式,因此可以并发发送 HTTP 请求,能够提高 HTTP 请求的效率

    请求管道化

  • Host头字段:HTTP/1.0 没有 host 字段,HTTP/1.1 新增了 host 字段,通过 Host 头部字段,一个物理服务器可以承载多个域名或站点

    Host头字段

  • 错误响应码:在 HTTP 1.1 中,新增了 24 个错误状态响应码

    • 例如: 409(Conflict):表示请求的资源与资源的当前状态发生冲突
    • 410(Gone):表示服务器上的某个资源被永久性的删除
  • 缓存处理:HTTP 1.0 中,主要使用 header 头里的 If-Modified-since、Expires 来做为缓存判断
    的标准;HTTP 1.1,则引入了更多的缓存控制策略,如:Entity tag、If-Unmodified-since、If-Match、If-None-Match等

  • 带宽优化及网络连接的使用:HTTP 1.0 中,存在一些浪费带宽的现象,例如:客户端只是需要某个对象的一部分,而服务器却将整个对象传送了过来,并且不支持断点续传功能;HTTP 1.1 中,则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样方便开发者自由的选择,以便于充分利用带宽和连接

详细链接:阿里一面:HTTP 1.0 和 HTTP 1.1 有什么区别?-51CTO.COM


HTTP/1.1 和 HTTP/2.0 的区别?

答:

  • 我认为 HTTP/1.1 和 HTTP/2.0 最大的区别在于:
    • HTTP/1.1 无法实现请求和响应的并发传输,而HTTP/2.0 能够实现请求和响应的并发传输
      • 原因:HTTP/1.1 虽然支持了管道化请求模式,能够并发传输 HTTP 请求,但是 HTTP 响应还是需要按顺序返回,无法做到 HTTP 响应并发传输。HTTP/2.0 引入了 stream 的概念,不同的 HTTP 请求和响用不同的 stream 来区分,多个 stream 复用一条 TCP 连接,只需要一条连接就可以达到了并发传输的效果
    • HTTP2.0 在 HTTP 报文格式上也做了改进,HTTP2.0 用了 HPACK 算法压缩了 HTTP 头部,同时将HTTP/1.1 纯文本的格式改进成了二进制格式,提高了数据传输的效率。HTTP2.0 还支持服务器主动推送资源,比如:客户端在从服务器获取 HTML 文件时,可能这个页面渲染还需要其他 CSS,这时候服务器可以接主动推送 CSS 文件,可以减少了消息传递的次数

补充:

HTTP/2.0 相比 HTTP/1.1 性能上的改进:

  1. 并发传输(最重要的区别)
  2. 头部压缩 + 二进制格式
  3. 服务器主动推送资源

详细链接:3.6 HTTP/2 牛逼在哪? | 小林coding


HTTP/2.0 和 HTTP/3.0 的区别?

答:

  • HTTP 2.0 和 3.0 最大区别:传输层使用的协议不同。以往 HTTP 都是基于 TCP 协议进行传输,这次HTTP3.0 改用 UDP 协议
    • HTTP/2.0 并发传输的特性,是在一条 TCP 连接上实现的这里会有 TCP 队头阻塞的问题,在传输过程中,假设:某个 stream 发生了丢包,服务端不仅不能处理这个stream,也不能处理其他 stream,必须等这个包重传了,才能继续处理其他 stream
    • 为了解决这个问题 HTTP/3.0 将传输层改用 UDP 协议,并在 UDP 基础上实现了一个可靠传输的 QUIC 协议,当某个流发生丢包时,只会阻塞这个 stream ,其他 stream 不会受到影响,因此不存在队头阻塞问题
  • 除此之外:
    • HTTP/3.0 连接建立方面比 HTTP/2.0 更高效,HTTP/2.0 建立连接的时候需要 3 次 TCP 握手 + TLS 四次握手,而 HTTP3.0 的 QUIC 协议只需要 3 次握手就能完成连接建立(包括 TLS 握手建立)
    • 最后还有一点,HTTP/3.0 在网络环境切换的过程,可以不需要重新建立连接。以往 HTTP 都是基于 TCP 协议进行传输,TCP 是根据 四元组信息 唯一确认一条连接,如果 四元组信息 某一个信息发生变化了,这时候就需要断开连接,重新建立连接,比如:4G 网络切换到 WIFI 网络的时候,所有的 TCP 连接都需要重新建立,而 HTTP/3.0 是在应用层通过连接 ID 来唯一确认连接的,即使网络发生切换,也不会影响原本的连接,消除重连的成本

补充:

  • 先提出 HTTP 2.0 的缺陷,存在 TCP 队头阻塞问题,,然后再提 HTTP/3.0 是怎么解决的,最后再提 HTTP3.0 还有什么新特性

详细链接:3.7 HTTP/3 强势来袭 | 小林coding


HTTP 是无状态的吗?

答:

是的,HTTP 是无状态的,一般我们会通过 Cookie、Session、Token 这些机制来维护用户的状态

补充:

  • HTTP 是 无状态 的,这意味着 每个请求都是独立的,服务器不会在多个请求之间保留关于客户端状态的信息,在每个 HTTP 请求中,服务器不会记住之前的请求或会话状态,因此每个请求都是相互独立的
  • 因此 服务器不知道请求两次之间是否是同一个用户。这会带来一个问题,用户登录后,切换到其他界面,进行操作,服务器端是无法判断是哪个用户登录的,每次进行页面跳转的时候,得重新登录
  • 虽然 HTTP 本身是无状态的,但可以通过一些机制来实现状态保持,其中最常见的方式是:使用 Cookie、Session、Token 来跟踪用户状态。通过在客户端存储会话信息或状态信息,服务器可以识别和跟踪特定用户的状态,以提供一定程度的状态保持功能

HTTP 用户后续的操作,服务端如何知道属于同一个用户?

如果服务端是一个集群机器?

答:

问题1:

  • 可以使用 Session Cookie 的机制 ,达到身份识别的效果
  • 比如:我用 账号 和 密码 登录某电商,登录成功后,网站服务器会校验 用户 和 密码,如果没问题,网站服务器就会生成一个唯一 session id 来标识我,然后将该 session id 设置到 Cookie 中发送给客户端,客户端再次访问网站时,会将该 Cookie 发送给服务器,服务器通过 Cookie 中的 Session ID 可以获取用户之前的状态信息,免去了重复登录的麻烦,实现了状态保持

补充:

HTTP 是 无状态 的,可以通过 Session Cookie 机制保持用户登陆的状态

image-20241226140419599

  1. 用户 向 服务器 发送 用户名 和 密码
  2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如:用户角色、登录时间等等
  3. 服务器向用户返回一个 session id,写入用户的 Cookie(响应头字段 Set-Cookie=session id)
  4. 用户随后的每一次请求,都会通过 Cookie(请求头字段 Cookie),将 session id 传回服务器
  5. 服务器收到 session id,找到前期保存的数据,由此得知用户的身份

问题2:

  • 如果服务端是一个 集群机器 的话, 可以用一台 Redis 来保存 session 数据,达到共享 session 的效果,不过这种方案存在 单点 的问题,如果 Redis 挂了,可能所有用户登陆状态都会消失了,虽然可以通过搭建 Redis 集群来保证避免 单点 问题,但是我觉得这个方案成本太高了
  • 一种比较低的解决成本方案是,不用 session,而是改用 JWT 来实现用户凭证会比较好,因为 JWT 的状态信息是保存在客户端的,服务端不再保存状态信息,天然适合分布式系统

补充:

  • seesion 这种方式扩展性不好,因为 session 状态信息是保存在服务器内存的,如果服务器是 集群,就要求 session 数据共享到每一台服务器,否则会出问题,比如:客户端登陆后,如果有一台服务器的内存没有 session id 的状态信息,当客户端请求到这台服务器后,服务器发现 session id 的状态信息不存在,就会让客户端重新进行用户登陆

    Session集群复制

  • 解决方案:

    • 第一种方案:将 session id 集中保存在 redis 或者 MySQL,服务器集群通过判断 session id 的状态信息在不在 redis 或者 MySQL,来确定用户是否已经登陆

    • 这种方案的缺陷是 单点故障 的问题(虽然也可以对 redis 搭建集群,但是架构的成本太高了)

      解决方案一

    • 第二种方案:服务器索性不保存 session 数据了,把状态信息保存在客户端,每次请求都发回服务器,这个就是 token 机制,为了保证 token 不被中间人篡改,可以 使用 JWT 的方式来进行身份识别,通常分布式系统都是采用 JWT 来进行身份状态识别

      JWT认证

详细链接:凭证 | 凤凰架构


如果禁用 Cookie,怎么实现 Session?

答:

可以通过重写 URL 来实现 Session 机制,就是在 URL 中增加 session id 请求参数

补充:

  • 禁用 Cookie 代表无法使用响应头无法使用 Set-Cookie 字段,以及请求头无法使用 Cookie 字段,这时候就没办法通过 HTTP Cookie 传输 Session id 了

  • 这时候可以重写 URL,比如:

    1
    2
    原始的URL: http://taobao.com/getitem?name=baymax&action=buy
    重写后的uRL:http://taobao.com/getitem?sessionid=1wui87htentg&name=baymax&action=buy

答:

  • 存储位置:Cookie 存储在浏览器,Session 存储在服务端
  • 存储大小:Cookie 是存储在浏览器的,浏览器对单个 Cookie 存储大小有限制的,限制保存的数据不能超过 4K,而 Session 是存储在服务端的,所以没有这个限制
  • 安全性:Cookie 存储在客户端,比较容易遭到不法获取,会容易遭到 XSS 和 CSRF 的攻击,而 Session 存储在服务端,安全性相对 Cookie 要好一些
  • 有效期:Cookie 可设置为长时间保持,比如:经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效

补充:

  • Cookie 是 服务器 发送到 用户浏览器 并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上
    • 通常,它用于 告知服务器两个请求是否来自同一浏览器。如:保持用户的登录状态,Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能
  • Session 代表着 服务器 和 客户端 一次会话的过程。Session 对象存储 特定用户会话 所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当客户端关闭会话,或者 Session 超时失效时会话结束
  • Cookie 和 Session 都是 Web 开发中用于跟踪用户状态的技术,但它们在 存储位置、存储大小、安全性、生命周期 等方面存在显著差异:
  • 存储位置:
    • Cookie 的数据存储在客户端(通常是浏览器)。当 浏览器 向 服务器 发送请求时,会自动附带 Cookie 中的数据
    • Session 的数据存储在服务器端。服务器为每个用户分配一个唯一的 Session ID,这个 ID 通常通过 Cookie 或 URL 重写的方式发送给客户端,客户端后续的请求会带上这个 Session ID,服务器根据 ID 查找对应的 Session 数据
  • 存储大小:
    • 单个 Cookie 的大小限制通常在 4KB 左右,而且大多数浏览器对每个域名的总 Cookie 数量也有限制
    • 由于 Session 存储在服务器上,理论上不受数据大小的限制,主要受限于服务器的内存大小
  • 安全性:
    • Cookie 相对不安全,因为数据存储在客户端,容易受到 XSS(跨站脚本攻击)的威胁。不过,可以通过设置 HttpOnly 属性来防止 JavaScript 访问,减少 XSS 攻击的风险,但仍然可能受到CSRF(跨站请求伪造)的攻击
    • Session 通常认为比 Cookie 更安全,因为敏感数据存储在服务器端。但仍然需要防范 Session 劫持(通过获取他人的Session ID)和会话固定攻击。
  • 生命周期:
    • Cookie 可以设置过期时间,过期后自动删除。也可以设置为会话 Cookie,即:浏览器关闭时自动删除
    • Session 在默认情况下,当用户关闭浏览器时,Session 结束。但服务器也可以设置 Session 的超时时间,超过这个时间未活动,Session也会失效

Cookie、session 和 Token 有什么区别?

答:

  • 存储位置不同:
    • Cookie 存储在 客户端,即:浏览器中的文本文件,通过在 HTTP 头中传递给服务器来进行通信
    • Session 是 服务器端 的存储方式,通常存储在服务器的内存或数据库中
    • Token 也是存储在 客户端,但是通常以加密的方式存储在客户端的 localStorage 或 sessionStorage 中
  • 数据安全性不同:
    • Cookie 存储在 客户端,可能会被窃取或篡改,因此对敏感信息的存储需要进行加密处理
    • Session 存储在 服务器端,通过一个 Session ID 在客户端和服务器之间进行关联,可以避免敏感数据直接暴露
    • Token 通常使用 加密算法 生成,有效期较短且单向不可逆,可以提供较高的安全性
  • 跨域支持不同:
    • 为了防止安全事故,因此 Cookie 是不支持跨域传输的,也就是不同域名下的 Cookie 是不能相互访问
    • Session 机制通常是通过 Cookie 来保存 Session ID 的,因此 Session ID 默认情况下也是不支持跨域的
    • 但 Token 可以轻松实现跨域,因为 Token 是存储在客户端的 localStorage 或者作为请求头的一部分发送到服务器的,所以不同的域名 Token 信息传输通常是不受影响的
  • 状态管理不同:
    • Cookie 是应用程序通过在客户端存储临时数据,用于实现状态管理的一种机制
    • Session 是服务器端记录用户状态的方式,服务器会为每个会话分配一个唯一的 Session ID,并将其与用户状态相关联
    • Token 是一种用于认证和授权的一种机制,通常表示用户的身份信息和权限信息

补充:

Cookie、Session 和 Token 通常都是用来保存用户登录信息的技术,但三者有很大的区别,简单来说:Cookie 适用于 简单的状态 管理,Session 适用于 需要保护用户敏感信息的场景,而 Token 适用于 状态无关的身份验证和授权


简述 JWT 的原理和校验机制?

答:

  • JWT 令牌是由 3 个部分组成,分别是:头部、负载、签名
    • 头部:描述令牌使用的签名算法,负载:描述的是用户信息,比如:用户名称、过期时间等等
    • 头部 和 负载 都是 不会被加密 的,只是会用 base64 编码
    • 最后一部分是 签名,是对 头部 和 负载 两部分数据的签名,签名的过程是,使用 头部 的签名算法,通过 服务器的密钥 对 前面两部分 内容进行 加密 计算
  • 校验 JWT 令牌的过程:
    • 服务端 收到 客户端 发过来的 JWT 令牌后,服务端 会取出 头部 和 负载 数据,然后用自己的 密钥 对 这两部分数据 进行 加密 计算,将得到的 加密结果 和 客户端 发过来 JWT 的签名进行对比
    • 如果相同,就表示前面两部分没有被中间人篡改,这时候服务器就可以进行其他验证,比如:检查 JWT 是否过期,如果也没问题,就会正常执行业务逻辑

补充:

JWT令牌

  • 左边的字符串呈现了 JWT 令牌的本体,右边的 JSON 结构是 JWT 令牌中携带的信息

JWT格式

  • JWT 格式是 header.payload.signature

  • JWT 共由 3 个部分信息组成:

    • Header(头部):描述了 令牌的类型(统一为 type:JWT)以及 令牌签名的算法(默认 HMACSHA256 算法),header 信息不做加密,只做一般的 base64 编码,目的是替换 URL 里面有特殊含义

      Header头部

    • Payload(负载):这是 令牌真正需要向服务端传递的信息。针对 认证 问题,负载至少应该包含能够告知服务端 “这个用户是谁” 的信息,JWT 的负载部分是可以完全自定义的,根据具体要解决的问题不同,设计自己所需要的信息。Payload 信息不做加密,只做一般的 base64 编码,目的是替换 URL 里面有特殊含义

      Payload负载

    • Signature(签名):是对前两部分的签名,防止数据篡改。签名的意思是:使用在 Header 中公开的特定签名算法,通过特定的密钥(Secret,由服务器进行保密,不能公开)对前面两部分内容进行加密计算

      Signature签名

  • 验证 JWT 令牌的流程:

    1. 服务端 收到 客户端 发过来 JWT 令牌之后,取出 header + payload,然后 服务端 根据自己的加密密钥进行加密计算
    2. 然后把 加密 的结果和 客户端 发过来 JWT 的 signature 进行对比,如果完全相同,则表示前面两部分没有动过,就是自己颁发的,如果不同,肯定是被篡改过了
    3. 当令牌验证为没有被篡改后,服务器可以进行其他验证,比如:是否过期、用户是否有权限访问 等等

JWT 令牌为什么能解决集群部署?

答:

JWT 包含 身份验证 和 会话信息,可以让服务器无需存储会话信息,就让服务器成为无状态的了,从而比较容易实现扩展

补充:

  • JWT 令牌通过在令牌中包含所有必要的 身份验证 和 会话信息,使得服务器无需存储会话信息,从而解决了集群部署中的身份验证和会话管理问题。当用户进行登录认证后,服务器将生成一个 JWT 令牌并返回给客户端。客户端在后续的请求中携带该令牌,服务器可以通过对令牌进行验证和解析来获取用户身份和权限信息,而无需访问共享的会话存储
  • 由于 JWT 令牌是自包含的,服务器可以独立地对令牌进行验证,而不需要依赖其他服务器或共享存储
  • 这使得集群中的每个服务器都可以独立处理请求,提高了系统的可伸缩性和容错性

JWT 有什么缺点?

答:

  • JWT 的最大缺点是 令牌难以主动失效,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器搞了额外的逻辑,比如:设计一个 “黑名单” 的额外的逻辑,用来把要主动失效的令牌集中存储起来,然后,每次使用 JWT 进行请求的话都会先判断这个 JWT 是否存在于黑名单中
  • JWT 要防止盗用的问题,因为 JWT 包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限,为了减少盗用,JWT 的有效期应该设置得比较短,而且不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输

补充:

JWT 的缺点:

  • 令牌难以主动失效:JWT 令牌一旦签发,理论上就和认证服务器再没有什么瓜葛了,在到期之前就会始终有效,除非服务器部署额外的逻辑去处理失效问题,这对某些管理功能的实现是很不利的
    • 譬如一种颇为常见的需求是:要求一个用户只能在一台设备上登录,在 B 设备登录后,之前已经登录过的 A 设备就应该自动退出。如果采用 JWT,就必须设计一个 “黑名单” 的额外的逻辑,用来把要主动失效的令牌集中存储起来,而无论这个黑名单是实现在 Session、Redis 或者 数据库 中,都会让服务退化成有状态服务,降低了 JWT 本身的价值,但黑名单在使用 JWT 时依然是很常见的做法,需要维护的黑名单一般是很小的状态量,许多场景中还是有存在价值的
  • 必须考虑令牌在客户端如何存储:严谨地说,这个并不是 JWT 的问题而是系统设计的问题。如果授权之后,操作完关掉浏览器就结束了,那把令牌放到内存里面,压根不考虑持久化才是最理想的方案。但并不是谁都能忍受一个网站关闭之后下次就一定强制要重新登录的。这样的话,想想客户端该把令牌存放到哪里 是 Cookie?、localStorage?、Indexed DB?它们都有泄漏的可能,而令牌一旦泄漏,别人就可以冒充用户的身份做任何事情。为了减少盗用,JWT 的有效期应该设置得比较短,而且 JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输

什么是跨域?什么情况下会发生跨域请求?

答:

  • 当一个网页去尝试访问不同源的资源的时候,就意味着发生了 跨域请求,只要 域名、协议、端口 这三个信息任意一个不同,都认为是不同源的 URL
  • 跨域请求 在 浏览器 上是 不被允许的,只要在浏览器上发生跨域请求操作时,浏览器就会自动抛出的错误。如果想绕过这个限制,可以用 跨域资源共享(CORS)技术
    • 实现的方式:服务器需要在 响应头 上添加 Access-Control-Allow-Origin 的字段,这个字段是设置为需要放行的域名,浏览器识别到了,才能放行该请界

补充:

  • 在浏览器环境下,当一个网页的脚本尝试去访问不同源(域名、协议、端口)的资源时,就会发生跨域请求。同源策略 是 浏览器 的一种安全机制,它限制了一个网页中的脚本只能访问同源下的资源,而不能直接访问其他域下的资源
  • 在以下情况下会发生跨域请求:
    1. 域名不同:当浏览器中的网页从一个域名(例如:www.example.com)发起请求访问另一个域名(例如:api.example.com)的资源时,就会发生跨域请求
    2. 协议不同:当浏览器中的网页从一个协议(例如:http://)发起请求访问另一个协议(例如:https://)的资源时,也会发生跨域请求
    3. 端口不同:当浏览器中的网页从一个端口(例如:http://example.com:8080)发起请求访问另一个端口(例如:http://example.com:3000)的资源时,同样会发生跨域请求。
  • 跨域请求会受到 同源策略 的限制,可以通过下面这些方式绕过限制:
    1. 使用反向代理:通过 Nginx 等工具设置反向代理,将跨域请求转发到目标服务器
    2. JSONP:网页通过添加一个 script 元素,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。缺点是:只支持 get 请求,不支持 post 请求
    3. CORS:在服务端设置响应头部信息,允许特定源的请求访问

详细链接:跨域是个什么鬼,你搞明白了吗?-跨域是指什么


RestFul 是什么?RestFul 请求的 URL 有什么特点?

答:

  • RestFul 是一种 API 接口设计规范,用 URL 定位资源,用 HTTP 方法表示接口的动作,用 HTTP 状态码表示接口处理的情况
  • RestFul 风格的 HTTP 接口可以通过 URL 就能判定这个接口是做什么的
    • /articles POST :代表新增一个文章
    • /articles GET :代表获取全部文章
    • 有可能后边带参数进行一些过滤查询或分页,/articles/1 GET:代表获取 id 为 1 这篇文章
    • /articles/1 PUT:代表更新 id 为 1 的文章
    • 请求体可能会带一些更新内容,/articles/1 DELETE:代表删除 id 为 1 的文章

补充:

RestFul 简单理解就是用 URL 定位资源,用 HTTP 动词(GET、POST、DELETE、PUT)描述操作

详细链接:RESTful API 设计指南 - 阮一峰的网络日志、(13 封私信 / 33 条消息) 怎样用通俗的语言解释REST,以及RESTful? - 知乎


HTTPS


HTTP 和 HTTPS 有什么区别?

答:

我的理解主要有 4 个方面的区别:

  • 安全性:HTTP 是明文传输协议,数据在传输过程中不加密,容易被窃听和篡改。而 HTTPS 通过使用 SSL/TLS 协议对数据进行加密,提供了更高的安全性和数据保护
  • 建立连接:HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输
  • 端口号:HTTP 默认使用 端口号 80 进行通信,而 HTTPS 默认使用端口号 443
  • 证书:HTTPS 需要使用数字证书来验证服务器的身份,并确保数据传输的安全性。证书由受信任的第三方机构颁发,用于证明服务器的身份和所有权。而 HTTP 没有使用证书进行身份验证和加密

了解过哪些加密算法?

答:

  • 我主要了解 对称加密算法、非对称加密算法、哈希算法 这三种加密算法:
  • 在 HTTPS 协议里,对称加密算法 和 非对称加密算法 这两种算法都会用到
    • 对称加密算法就是用一个密钥进行加解密,比如:AES 算法;非对称加密则是有 2 个密钥,分别是 公钥和 私钥,比如:RSA算法。对称加密算法 适用于 大量数据 的 加密 和 解密,而 非对称加密算法 适用于 密钥交换 和 数字签名 等场景
  • 哈希算法 主要用过 MD5 算法,哈希算法 是一种 单向算法,用户可以通过 哈希算法 对目标信息生成一段特定长度的唯一的哈希值,却不能通过这个哈希值重新获得目标信息,所以用于数据完整性校验方面

详细链接:常用的加密算法_51CTO博客_常用的加密算法有哪些


对称加密和非对称加密是什么?各自有哪些算法?

答:

  • 对称加密 和 解密 都是用 同一个密钥 进行操作,加密 和 解密 过程速度较快,适合对大量数据进行加密,对称密钥必须保密,不能明文传输,常见的对称加密算法有 AES、DES等
  • 非对称加密使用 两个密钥,分别是 公钥 和 私钥,加密 和 解密 过程相对较慢,适合对少量数据进行加密。公钥 可以 任意分发,而 私钥 必须 保密,可以通过 公钥加密对称密钥,私钥解密 的方式,保证对称密钥的安全传输,常见的非对称加密算法有 RSA、ECC 等

补充:

  • 密钥区别:

    1. 对称加密:使用同一个密钥进行加密和解密。这意味着加密方和解密方必须事先共享同一个密钥,并且保证这个密钥的安全
    2. 非对称加密:使用一对密钥,一个公开密钥(公钥)用于加密,一个私有密钥(私钥)用于解密。公钥可以公开分享,而私钥必须保持私密
  • 加密速度区别:

    1. 对称加密:通常更快,因为它使用较简单的算法来处理大量数据
    2. 非对称加密:由于其复杂的数学运算,尤其是在处理大量数据时,比对称加密得多
  • 使用场景区别:

    1. 对称加密:适用于需要快速处理大量数据的场景,如:文件加密、数据库加密、网络数据传输加密等
    2. 非对称加密:由于其速度较慢,通常用于加密少量数据或用于加密对称加密中使用的密钥
  • 典型的加密算法:

    • 对称加密算法:AES(高级加密标准)、DES(数据加密标准)、3DES(三重数据加密算法)等

      对称加密算法

    • 非对称加密算法:RSA、ECC(椭圆曲线密码学)等

      非对称加密算法

详细链接:浅谈常见的七种加密算法及实现数字签名、信息加密 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通 - 掘金


对称和非对称的加密算法的区别?

答:

  • 我理解的区别:
    1. 对称 加密 和 解密 都是用 同一个密钥 进行操作,加密和解密过程速度较快,适合对大量数据进行加密,对称密钥必须保密,不能明文传输
    2. 非对称 加密使用 两个密钥,分别是 公钥 和 私钥,加密和解密过程相对较慢,适合对少量数据进行加密。公钥可以任意分发,而私钥必须保密,可以通过公钥加密对称密钥,私钥解密的方式,保证对称密钥的安全传输
  • HTTPS 采用的就是这样的混合加密方式
    • 在 通信建立前 采用 非对称加密 的方式 交换「对称密钥」,后续就不再使用非对称加密。在 通信过程中 全部 使用「对称密钥」的方式加密明文数据

补充:

可以从 加解密速度 + 密钥传输安全性 两个方向来说明区别


假设有一个文件,大小未知,现在要把它上传到云端,该使用对称加密还是非对称加密算法?

答:

使用对称加密算法比较好,因为对称加密算法运算速度是比非对称加密更快的,比较适合数据量大常见的加密

补充:

  • 对称密钥加密速度会比非对称密钥快,针对数据量比较大的场景,要选择对称密钥来加密。对称加密比非对称加密快的原因:
    • 对称加密 主要的运算是 位运算,速度非常快,如果使用硬件计算,速度会更快,但是非对称加密计算一般都比较复杂,比如:RSA,它里面涉及到 大数乘法、大数模 等等运算
    • 除了慢,可能还有一个缺点就是需要更多的位数,相同强度的对称密钥要比非对称密钥短。对称密钥一般都 128 位、256 位,而 RSA 一般要 2048 位,不过圆曲线的会短一点

详细链接:为什么非对称加密比对称加密慢?-腾讯云开发者社区-腾讯云


HTTPS 建立的过程是怎么样的?

答:

  • 首先 客户端 要和 服务端 先进行 TCP 三次握手建立 TCP 连接。接下来,会进行 TLS 四次握手:
    1. 第一次 TLS 握手:客户端首先会发一个 Client Hello 消息,消息里面有 客户端使用的 TLS 版本号、支持的密码套件列表、客户端生成的随机数,这个随机数是用来后面生成对称密钥元素之一
    2. 第二次 TLS 握手:当服务端收到客户端的消息后,会返回 Server Hello 消息给的客户端,消息里面有服务器确认的 TLS 版本号、密码套件、服务端生成的随机数。接着服务端为了证明自己的身份,会发送 Server Certificate 给客户端,这个消息里含有数字证书。随后,服务端发了 Server Hello Done 消息,目的是告诉客户端,我已经把该给你的东西都给你了,本次握手完毕
      • 校验证书:客户端收到服务端的数字证书的时候,会对校验服务端的证书,如果证书是合法的,客户端会用 CA 机构的公钥解密数字证书拿到服务端的公钥
    3. 第三次 TLS 握手:客户端再次生成一个随机数,用服务端的公钥加密后,通过 Client Key Exchange 消息传给服务端。服务端收到后,用服务端的私钥解密得到客户端的第二个随机数。到这里,服务端和客户端双方都有 3 个随机数,双方根据已经得到的三个随机数,会根据算法生成对称密钥。生成完对称密钥后,客户端会发一个消息告诉服务端开始使用对称加密方式发送消息,并且还会对之前所有发送的数据做个摘要,再用对称加密加密一下,让服务器做个验证,验证对称密钥是否可用,以及之前握手信息是否有被中途篡改
    4. 第四次 TLS 握手:服务器也是同样的操作,发送消息告诉客户端开始用对称加密方式发送消息,并且也会对数据做个摘要,并用对称密钥加密一下,让客户端做个校验,如果双方都验证加密和解密没问题,那么 TLS 四次握手正式完成了
  • 最后,就用对称密钥加解密 HTTP 请求和响应了

补充:

HTTPS建立过程

HTTPS建立过程

详细链接:3.3 HTTPS RSA 握手解析 | 小林coding


为什么需要三个随机数?

答:

因为计算机生成的随机数其实是一个伪随机,那么只用一个随机数来生成的对称密钥很容易就被破解了,用三个伪随机数就十分接近随机了,这样称密钥破解的难度都变高了

补充:

  • 不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于 SSL 协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性
  • 对于 RSA 密钥交换算法来说,pre-master-key(第三个随机数)本身就是一个随机数,再加上 hello 消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥
  • pre master(第三个随机数)的存在在于 SSL 协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret(第三个随机数)作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上 pre master secret 三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一

详细链接:SSL/TLS协议运行机制的概述 - 阮一峰的网络日志


一次HTTPS需要几次RTT(就是几个来回)?

答:

HTTPS 是四次握手,那么就是 2 次 RTT

补充:

RTT 是往返的延时,HTTPS 是四次握手,也就是代表 2 次往返,那么就是 2 次 RTT

详细链接:3.3 HTTPS RSA 握手解析 | 小林coding


你了解业界现在有一个RTT建立HTTPS连接的方案吗?

答:

基于 ECDHE 密钥交换的 HTTPS 连接方案,可以实现1 个 RTT 建立 HTTPS 连接

补充:

  • TLS 1.2 版本如果使用的是 RSA 密钥交换算法,那么需要 4 次握手,也就是要花费 2 RTT,才可以进行应用数据的传输

  • 因此如果可以,尽量选用 ECDHE 密钥交换算法(TLS 1.3 版本使用)替换 RSA 算法,因为该算法由于支持「TLS False start」,客户端可以在 TLS 协议的第 3 次握手后,第 4 次握手之前,发送加密的应用数据,以此将 TLS 握手的消息往返由 2 RTT 减少到 1 RTT

    TSL四次握手

  • 下图左边是基于 RSA 算法的 HTTPS 建立流程,需要 2 个 RTT,右边是基于 ECDHE 算法的 HTTPS 建立流程,只需要 1 个 RTT

    RSA算法与ECDHE算法的对比

    • 上图的右边部分就是 TLS 1.3(基于 ECDHE 算法)的握手过程,可以发现 TLS 1.3 把 Hello 和 公钥 交换这两个消息合并成了一个消息,于是这样就减少到只需 1 RTT 就能完成 TLS 握手
    • 具体的做法是:客户端在 Client Hello 消息里带上了支持的椭圆曲线,以及这些椭圆曲线对应的公钥,服务端收到后,选定一个椭圆曲线等参数,然后返回消息时,带上服务端这边的公钥。经过这 1 个 RTT,双方手上已经有生成会话密钥的材料了,于是客户端计算出会话密钥,就可以进行应用数据的加密传输了
    • 服务端收到后,选定一个椭圆曲线等参数,然后返回消息时,带上服务端这边的公钥
    • 经过这 1 个 RTT,双方手上已经有生成会话密钥的材料了,于是客户端计算出会话密钥,就可以进行应用数据的加密传输了

详细链接:3.5 HTTPS 如何优化? | 小林coding、3.4 HTTPS ECDHE 握手解析 | 小林coding


HTTPS 过程进行了多少次非对称加密?多少次对称加密?

答:

  • 还未 HTTPS 握手之前:
    • 服务端在向 CA 机构注册证书的时候,CA 机构会用 CA 私钥会对服务端的公钥进行签名,形成数字证书,这里涉及了 1 次非对称加密
  • HTTPS 握手期间:
    • 客户端会用服务端的公钥加密随机数,服务端再用私钥解密,这里涉及了 1 次非对称加密
    • 客户端和服务端生成对称密钥之后,都需要对之前握手的数据做个摘要,并用对称密钥加密一下,这个过程客户端和操作都会涉及到,所以 HTTPS 握手期间用了 2 次对称加密,客户端和服务端各做了一次
  • HTTPS 握手完成之后:
    • HTTPS 数据传输期间都是用对称密钥进行加密和解密

补充:

  • 可以分 HTTPS 握手之前、期间、之后三个时间段来回答

详细链接:3.3 HTTPS RSA 握手解析 | 小林coding


SSL 握手流程为什么要使用非对称加密?

答:

  • 我的理解主要是为了保护对称加密钥不被中间人窃取,如果对称加密钥被窃取了,使用这个对称加密钥加密的 HTTP 报文就很容易被破解了
  • 在 HTTPS 协议进行 TLS 握手的时候,客户端生成随机数,这个是生成对称加密钥元素之一,它会被公钥加密后传输给服务端,由服务端用私钥解密,这里就保证了对称加密钥的安全
    • 因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容

详细链接:3.3 HTTPS RSA 握手解析 | 小林coding


为什么 HTTPS 不用非对称加密算法加密 HTTP 报文?

答:

非对称加密算法的加密和解密操作相对比对称加密算法更消耗 CPU 计算力,也更耗时,而 HTTP 报文通常包含大量的数据,如果直接使用非对称加密算法对整个报文进行加密和解密,会导致性能下降和延迟增加

补充:

要重点说明非对称加密算法更消耗 CPU 计算力,不适合用来频繁的加解密

详细链接:为什么非对称加密比对称加密慢?这个问题是一个读者面试时遇到的一个问题,准备过面试的人应该都记得,非对称加密与对称加密的区 - 掘金


HTTPS 会对 URL 加密吗?

答:

URL 是属于 HTTP 报文头部的信息,HTTPS 会对整个 HTTP 报文都会加密,所以 HTTPS 是会对 URL 加密的

补充:

很多人看到浏览器的地址栏就以为 HTTPS 不会对 URL 进行加密,实际上 URL 是属于 HTTP 报文头部的信息,HTTPS 会对整个 HTTP 报文(header + body)都加密,所以 HTTPS 是会对 URL 加密,之所以浏览器能明文显示 URL,是因为浏览器已经帮我们解密好了

详细链接:字节一面:HTTPS 会加密 URL 吗?


CA 机构如何验证server身份?

答:

服务端在向 CA 机构申请证书的时候,CA 机构会通过自己的私钥对服务器的一些信息进行数字签名,然后在 HTTPS 握手阶段的时候,服务端会发送证书给客户端来验证,客户端实际上已经内置了 CA 机构的公钥,那么就用这个公钥来验证服务端的数字证书是否是可信的

补充:

CA机构流程

CA机构流程


证书是绿色的是什么意思?

答:

代表网站是 可信的,浏览器在 HTTPS 握手阶段会对网站服务器下发的证书进行校验,,如果校验成功,代表网站的身份的可信的,是被 CA 机构认证过的

SSL证书是什么-什么是SSL证书-华为云


自己随便编一个证书可以吗?需要去什么地方注册?

答:

  • 不可以
    • 浏览器在校验这个证书的时候,会认为是非法的证书,这时候浏览器会显示访问的网站是不可信
    • 得去 CA 机构申请证书,浏览器才会认为是合法的证书,这样才能正常的访问网站的内容

补充:

  • 数字证书的作用:是用来认证 公钥持有者 的身份,以防止第三方进行冒充
    • 说简单些,证书就是用来告诉客户端,该服务端是否是合法的,因为只有证书合法,才代表服务端身份是可信的。我们用证书来认证公钥持有者的身份(服务端的身份)
  • 那证书又是怎么来的?又该怎么认证证书呢?为了让服务端的公钥被大家信任,服务端的证书都是由 CA (Certificate Authority,证书认证机构)签名的,CA 就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名,信任的一方签发的证书,那必然证书也是被信任的

详细链接:3.3 HTTPS RSA 握手解析 | 小林coding


RPC


RPC 的作用是什么?

答:

  • RPC 是远程过程调用,主要运用于微服务之间的通信
  • 它的作用是帮助我们屏蔽网络编程细节,实现调用远程方法就跟调用本地(同一个项目中的方法)一样的体验,让我们更专注于业务逻辑,而无需关注底层网络通信的细节

补充:

  • RPC 的全称是 Remote Procedure Call,即:远程过程调用。简单解读字面上的意思,远程肯定是指要跨机器而非本机,所以需要用到网络编程才能实现,但是不是只要通过网络通信访问到另一台机器的应用程序,就可以称之为 RPC 调用了?显然并不够
  • 我理解的 RPC 是帮助我们屏蔽网络编程细节,实现调用远程方法就跟调用本地(同一个项目中的方法)一样的体验,我们不需要因为这个方法是远程调用就需要编写很多与业务无关的代码。这就好比建在小河上的桥一样连接着河的两岸,如果没有小桥,我们需要通过划船、绕道等其他方式才能到达对面,但是有了小桥之后,我们就能像在路面上一样行走到达对面,并且跟在路面上行走的体验没有区别
  • 所以我认为,RPC的作用就是体现在这样两个方面:
    • 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法
    • 隐藏底层网络通信的复杂性,让我们更专注于业务逻辑

为什么有HTTP协议了?还要用RPC?

答:

  • HTTP 和 RPC 其实是两个维度的东西, HTTP 指的是 通信协议。而 RPC 则是远程调用,其对应的是本地调用。RPC 的通信可以用 HTTP 协议,也可以自定义协议,是不做约束的
  • 用 HTTP 传输数据会有比较多的信息,比如:头部有各种字段信息,数据载体则一般是用 json 格式,而 RPC 因为它定制化程度更高,可以采用体积更小的 protobuf 或 其他序列化协议 去保存结构体数据,同时也不需要像 HTTP 那样考虑各种浏览器行为,比如:302 重定向跳转啥的,因此性能也会更好一些,这也是在公司内部微服务中抛弃 HTTP,选择使用 RPC 的最主要原因

补充:

  • RPC 本质上不算是协议,而是一种调用方式,而像 gRPC 和 Thrift 这样的具体实现,才是协议,它们是实现了 RPC 调用的协议。目的是希望程序员能像调用本地方法那样去调用远端的服务方法。同时 RPC 有很多种实现方式,不一定非得基于 TCP 协议
  • 从发展历史来说,HTTP 主要用于 B/S 架构,而 RPC 更多用于 C/S 架构。但现在其实已经没分那么清了,B/S 和 C/S 在慢慢融合。很多软件同时支持多端,所以对外一般用 HTTP 协议,而内部集群的微服务之间则采用 RPC 协议进行通讯
  • RPC 其实比 HTTP 出现的要早,且比目前主流的 HTTP/1.1 性能要更好,所以大部分公司内部都还在使用RPC
  • HTTP/2.0 在 HTTP/1.1的基础上做了优化,性能可能比很多 RPC 协议都要好,但由于是这几年才出来的
  • 所以也不太可能取代掉 RPC

详细链接:3.8 既然有 HTTP 协议,为什么还要有 RPC? | 小林coding


Nginx


Nginx 位于七层网络结构的哪一层?

答:

应用层,nginx 是七层负载均衡

补充:

OSI vs TCP/IP

  • 常说的七层和四层负载均衡,是用 OSI 网络模型来描述的,七层对应的是应用层,四层对应的是传输
    层

详细链接:讲讲亿级PV的负载均衡架构-腾讯云开发者社区-腾讯云


Nginx 有哪些负载均衡算法?

答:

  • 我了解到的主要有 普通轮询、加权轮询、IP 哈希、URL 哈希、最短响应时间、最短连接 这些负载均衡算法
  • 大体上可以分为下面几类:
    1. 任务平分类:负载均衡系统将收到的任务平均分配给服务器进行处理,这里的 “平均” 可以是绝对数量的平均,也可以是比例或者权重上的平均,比如:轮询 和 加权轮询算法
    2. 负载均衡类:负载均衡系统根据服务器的负载来进行分配,可以用 CPU 负载来衡量,也可以用连接数 I/O 使用率、网卡吞吐量等来衡量系统的压力。比如:最短连接数算法
    3. 性能最优类:负载均衡系统根据服务器的响应时间来进行任务分配,优先将新任务分配给响应最快的服务器,比如:最短响应时间算法
    4. Hash类:负载均衡系统根据任务中的某些关键信息进行Hash运算,将相同Hash值的请求分配到同一台服务器上,比如:IP哈希和URL算法

补充:

  • Nginx支持的负载均衡算法包括:
    1. 轮询:按照顺序依次将请求分配给后端服务器。这种算法最简单,但是也无法处理某个节点变慢或者客户端操作有连续性的情况
    2. 加权轮询:按照权重分配请求给后端服务器,权重越高的服务器获得更多的请求。适用于后端服务器性能不同的场景,可以根据服务器权重分配请求,提高高性能服务器的利用率
    3. IP哈希:根据客户端IP地址的哈希值来确定分配请求的后端服务器。适用于需要保持同一客户端的请求始终发送到同一台后端服务器的场景,如:会话保持
    4. URL哈希:按访问的URL的哈希结果来分配请求,使每个URL定向到一台后端服务器,可以进一步提高后端缓存服务器的效率
    5. 最短响应时间:按照后端服务器的响应时间来分配请求,响应时间短的优先分配。适用于后端服务器性能不均的场景,能够将请求发送到响应时间快的服务器,实现负载均衡
    6. 最短连接:新请求会发送到并发连接最少的服务节点

详细链接:面试官:你背一下负载均衡算法?


什么是反向代理?什么是正向代理?

答:

正向代理 代理的 客户端 这一方,而 反向代理 是代理 服务器 这一方,可以通过负载均衡策略,将请求分发到不同服务器上

补充:

  • 正向代理 是位于用户设备和互联网之间的服务器。它代理的是客户端,是站在用户一方的。其真实客户端对于服务器不可见
    • 正向代理通常用于:
      1. 保护客户端,隐藏客户端真实 IP,免受攻击
      2. 避免网络浏览限制(科学上网)
      3. 阻止访问某些内容
      4. 提高访问速度。通常代理服务器会有较大的硬盘缓冲区,将一些响应结果缓存在服务器端,以便后续用户取用
  • 反向代理 是一种服务器,它接受客户端的请求,将请求转发给网络服务器,然后将结果返回给客户端,就像代理服务器处理了请求一样
    • 反向代理代理的是服务器,是和网络服务器站在一方的。其真实服务器对于客户端不可见。这就是它叫 “反向” 的原因
    • 反向代理可用于:
      1. 保护服务器,隐藏服务器真实 IP
      2. 负载均衡,根据访问流量和服务器负载情况,将请求分发到不同服务器上
      3. 缓存静态内容以及部分短时间的大量动态请求
      4. 作为应用层防火墙提供防护,加密/解密 SSL 通信

TCP 三次握手


TCP头部有哪些字段?

答:

  • 我印象中 TCP 头部字段主要有 出序列号、确认号、源端口号、目的端口号、标记位:SYN、ACK、FIN、RST、头部长度、窗口大小,可扩展的选项这些
  • 其中,序列号和确认号都是 32 位大小,序列号可以保证数据的有序性,接收方会按照发送方顺序发送的数据来组装有序的数据,确认号可以保证数据的可靠性,当发送方已发送的数据,超过一段时间没收到确认报文,就会重传报文。然后,源端口号和目的端口号是 16 位大小,源端口是发送方使用的端口号,目的端口是接收方使用的端口号,端口的作用是标识 TCP 连接是哪个进程的

补充:

TCP报文段的首部格式

  • 源端口:16 位,标识报文的返回地址
  • 目的端口:16 位,指明接收方计算机上的应用程序接口
  • 序列号:32 位,在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就累加一次该数据字节数的大小。用来解决网络包乱序问题
  • 确认号:32 位,指下一次期望收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题
  • 数据偏移/首部长度:4 位,TCP 首部可能含有可选项内容,所以 TCP 报头的长度是不确定的,报头不包含任何任选字段则长度为 20 字节,4位首部长度字段所能表示最大长度为 60 字节。首部长度也叫数据偏移,因为首部长度实际上指示了数据区在报文段中的起始偏移值
  • 保留:6 位,为将来定义新的用途保留,现在一般置 0
  • 校验和:16 位,由发送端填充,接收端对 TCP 报文段执行 CRC 算法以检验 TCP 报文段在传输过程中是否损坏,这个校验不仅包括 TCP 头部,也包括数据部分。这是 TCP 实现可靠传输的一个重要保障
  • 窗口:16 位,是 TCP 流量控制的一个手段。通过窗口告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方可以控制发送数据的速度,从而达到流量控制。窗口大小为 16 bit字段,因而窗口大小最大为 65535
  • 紧急指针:16 位,只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。使用紧急指针是发送端向另一端发送紧急数据的一种方式
  • 选项和填充:TCP 头部的最后一个选项字段是可变长的可选信息。这部分最多包含40字节,因为 TCP 头部最长是 60 字节
    • 最常见的可选字段是最长报文大小 MSS,每个连接方通常都在通信的第一个报文段中指明这个选项,它表示本端所能接受的最大报文段的长度
  • 数据部分:TCP 报文段中的数据部分是可选的。在连接建立或者终止时,双方交换的报文段仅有 TCP 首部;如果一方没有数据要发送,也会使用没有任何数据的首部来确认收到的数据;在处理超时的许多情况中,也会发送不带任何数据的报文段

还包括控制位:

  • URG:紧急指针标志,为 1 时表示紧急指针有效,该报文应该优先传送,为 0 则忽略紧急指针
  • ACK:确认序号标志,为 1 时表示确认号有效,为 0 表示报文中不含确认信息。携带 ACK 标识的 TCP 报文段被称为确认报文段
  • RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接,或者用于拒绝非法的报文段和拒绝连接请求。称携带 RST 标志的 TCP 报文段为复位报文段
  • SYN:表示请求建立一个连接。称携带 SYN 标志的 TCP 报文段为同步报文段
  • FIN:finish 标志,用于释放连接,为 1 时表示发送方已经没有数据发送了,即关闭本方数据流。称携带FIN 标志的 TCP 报文段为结束报文段
  • PSH:push 标志,为 1 表示是带有 push 标志的数据,指示接收方在接收到该报文段以后,应优先将这个报文段交给应用程序,而不是在缓冲区排队

详细链接:TCP之报文首部格式 - Jummyer - 博客园


说一下TCP三次握手的过程?

答:

TCP 三次握手的过程:

  1. 最开始双方的 TCP 连接都处于 close 状态,服务端首先会监听一个端口,处于 Listen 状态
  2. 在第一次握手的时候,客户端会随机生成初始化序号,放到 TCP 报文头部的序号字段中,同时把 SYN 标志设置为 1,这样就表示 SYN 报文。接着把这个 SYN 报文发送给服务端,之后客户端处于 SYN_SENT状态
  3. 服务端收到 SYN 报文后,首先服务端也会随机生成初始化序号,放到 TCP 报文头部的序号字段中,然后对 客户端的初始化序号+1 作为确认号,放到 TCP 报文头部的确认应答字段中,并将 SYN 和 ACK 标志设置为 1,这样就表示 SYN-ACK 报文,后把该报文发给客户端,之后服务端处于 SYN_RCVD 状态
  4. 客户端收到服务端 SYN-ACK 报文后,客户端会回一个 ACK 确认报文,该报文的确认号是 服务端的初始化序号+1,并且 ACK 标志会设置为 1。之后客户端处于 ESTABLISHED 状态
  5. 服务端收到 ACK 确认报文后,服务端也进入处于 ESTABLISHED 状态

TCP三次握手的过程


为什么需要三次握手?两次不行吗?

答:

我的理解主要有两个原因:

  • 第一个原因是:三次握手可以有效防止历史连接的建立,避免资源浪费。假设:网络中残留一个序号为 90 的 SYN 报文,现在客户端向服务端发起了建立连接的请求,发送了一个序号为 100 的 SYN 报文,如果这时候服务端先收到的是序号为 90 的 SYN 报文,就代表收到了历史连接,这时候服务端会回复确认号为 90+1 的 SYN-ACK 报文,客户端收到后,发现其实自己期望收到的确认号是 100+1,而不是 90+1,所以会断开连接,并且回 RST 给服务端,服务端收到 RST 也就会断开连接了,这样就避免了历史连接的建立。如果是两次握手的话,服务端在收到第一次握手就会建立连接,如果这时候建立的历史连接,那么就会造成资源浪费了
  • 第二个原因是:三次握手可以确认客户端和服务端是否同时具备发送和接收的能力。第一握手代表客户端具有发送能力,当服务端收到第一次握手并且响应了第二次握手,实际上这里就证明了服务端具有发送和接收,客户端收到了第二次握手,然后响应了第三次握手,才代表客户端有接收的能力。如果是两次握手的话,只能证明服务端具有发送和接收能力,以及客户端的发送能力,但是无法证明客户端具有接收的能力。

以上就是我觉得 TCP 需要三次握手的原因


如果第一次握手丢包,会发生什么?

答:

如果第一次握手丢包了,达到超时重传的时机的话,会进行重传 SYN 报文,如果重传次数达到最大次数,还是没有收到第二次握手的话,客户端就会断开链接了

补充:

  • 当客户端想和服务端建立 TCP 连接的时候,首先第一个发的就是 SYN 报文,然后进入到 SYN_SENT 状态

  • 在这之后,如果客户端迟迟收不到服务端的 SYN-ACK 报文(第二次握手),就会触发「超时重传」机制,重传 SYN 报文,而且重传的 SYN 报文的序列号都是一样的

  • 不同版本的操作系统可能超时时间不同,有的 1 秒的,也有 3 秒的,这个超时时间是写死在内核里的,如果想要更改则需要重新编译内核,比较麻烦

  • 当客户端在 1 秒后没收到服务端的 SYN-ACK 报文后,客户端就会重发 SYN 报文,那到底重发几次呢?在 Linux 里,客户端的 SYN 报文最大重传次数由 tcp_syn_retries 内核参数控制,这个参数是可以自定义的,默认值一般是 5

  • 通常,第一次超时重传是在 1 秒后,第二次超时重传是在 2 秒,第三次超时重传是在 4 秒后,第四次超时重传是在 8 秒后,第五次是在超时重传 16 秒后。没错,每次超时的时间是上一次的 2 倍。当第五次超时重传后,会继续等待 32 秒,如果服务端仍然没有回应 ACK,客户端就不再发送 SYN 包,然后断开 TCP 连接。所以,总耗时是 1+2+4+8+16+32=63 秒,大约 1 分钟左右

  • 举个例子,假设 tcp_syn_retries 参数值为 3,那么当客户端的 SYN 报文一直在网络中丢失时,会发生下图的过程:

    第一次握手丢包

  • 具体过程:

    • 当客户端超时重传 3 次 SYN 报文后,由于 tcp_syn_retries 为 3,已达到最大重传次数,于是再等待段时间(时间为上一次超时时间的 2 倍),如果还是没能收到服务端的第二次握手(SYN-ACK 报文)那么客户端就会断开连接

如果第二次握手丢包,会发生什么?

答:

我的理解第二次握手 SYN-ACK 报文其实有两个目的

  1. 第一个是报文中的 ACK,是对第一次握手的确认报文,那么当第二次握手的丢失的时候,就会导致客户端长时间没有收到 ACK 而触发超时重传 SYN 报文(第一次握手)
  2. 第二个是报文中的 SYN,是服务端发起建立 TCP 连接的报文,那么当第二次握手的丢失的时候,服务端就收不到第三次握手,于是服务端这边会触发超时重传机制,重传 SYN-ACK 报文

补充:

  • 第二次握手的 SYN-ACK 报文其实有两个目的:
    1. 第二次握手里的 ACK, 是对第一次握手的确认报文
    2. 第二次握手里的 SYN,是服务端发起建立 TCP 连接的报文
  • 因为第二次握手报文里是包含对客户端的第一次握手的 ACK 确认报文,所以,如果客户端迟迟没有收到第一次握手,那么客户端就觉得可能自己的 SYN 报文(第一次握手)丢失了,于是客户端就会触发超时重传机制,重传 SYN 报文
  • 然后,因为第二次握手中包含服务端的 SYN 报文,所以当客户端收到后,需要给服务端发送 ACK 确认报文(第三次握手),服务端才会认为该 SYN 报文被客户端收到了。那么,如果第二次握手丢失了,服务端就收不到第三次握手,于是服务端这边会触发超时重传机制,重传 SYN-ACK 报文。

第二次握手丢包


如果第三次握手丢包,会发生什么?

答:

我的理解是第三次握手的 ACK 是对第二次握手的 SYN 报文的确认,所以当第三次握手丢失了,如果服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传 SYN-ACK 报文,直到收到第三次握手,或者达到最大重传次数

补充:

第三次握手丢包


TCP的半连接队列和全连接队列了解过吗?

答:

  • 半连接队列:服务端收到客户端发起的 SYN 请求后,内核会把未完成握手的连接存储到半连接队列,等待完成三次握手后转移到全连接队列
  • 全连接队列:服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到全连接队列,等待进程调用 accept 函数时把连接取出来

补充:

在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:

  • 半连接队列,也称 SYN 队列
  • 全连接队列,也称 accept 队列

服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来

TCP的半连接队列和全连接队列


TCP 四次挥手


TCP 四次挥手的过程?

答:

  1. 客户端打算关闭连接,此时会发送一个 FIN 报文,之后客户端进入 FIN_WAIT_1 状态
  2. 服务端收到 FIN 报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSE_WAIT 状态
  3. 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态
  4. 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态
  5. 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
  6. 服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭
  7. 客户端在 TIME_WAIT 状态经过 2MSL,一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭

以上就是四次挥手的过程,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手

TCP 四次挥手


为什么 TCP 需要四次挥手?三次挥手不行吗?

答:

  • 我的理解是 TCP 是全双工协议,双方都具备发送和接收的能力,那么在断开连接的期间,要确保双方能发送完自己的数据
  • 当客户端发送第一次挥手后,也就是 FIN 报文的时候,其实就代表客户端告诉服务端 “我不会再发送数据了”,服务端收到后,服务器收到客户端的 FIN 报文时,内核会马上回一个 ACK 应答报文,但是服务端应用程序可能还有数据要发送,所以并不能马上发送 FIN 报文,而是将发送 FIN 报文的控制权交给服务端应用程序,如果服务端应用程序有数据要发送的话,就发完数据后,才调用关闭连接的函数。所以第二次挥手和第三次挥手通常不会合并一起发送,而是分开发送,所以就需要四次挥手
  • 如果只有三次挥手,那么就可能出现一方还有数据没有发送完就被迫关闭连接的情况,这会导致数据的丢失

补充:

要重点表述四次握手的原因是,TCP 是全双工的协议,需要双方确认自己不再发送数据的时候,才会主动发送 FIN 报文


TIME_WAIT 是如何产生的?

答:

当 TCP 连接的主动关闭方关闭连接,与被动关闭方进行了四次挥手的时候,在主动关闭方发送完第四次挥手后,也就是最后一个 ACK 报文后,主动关闭方的 TCP 连接就会进入到 TIME_WAIT 状态,这个状态会持续 2MSL 的时长,以确保对方已经收到了最后一个 ACK 报文

补充:

TIME_WAIT 状态是发生在客户端,其实不是的,准确来说 TIME_WAIT 状态发生在主动关闭连接的一方,客户端和服务端都可以作为主动关闭连接的一方


为什么 TIME_WAIT 状态要等待 2MSL?

答:

我的理解主要有两个原因:

  • 第一个原因:主要是为了避免本次连接的历史报文,被新的连接接收到这些历史报文,从而导致出错 ,MSL 表示 TCP 报文在网络中最大的存活时长,等待 2MSL 就可以让两个方向的报文可以在网络中自然消失这样新的连接就不会接收到历史报文了
  • 第二个原因,是为了确保第四次挥手 ACK 报文能被接收,从而帮助被动关闭方正常关闭连接。如果主动关闭方的第四次挥手的 ACK 报文丢失了,由于被动关闭方没有收到这个 ACK 报文,它会超时重传 FIN 包,主动关闭方 TIME_WAIT 状态等待期间会重新发送 ACK 报文,如果没有 TIME_WAIT 状态,那么就没办法重新发生 ACK 报文,也就没办法帮助被动关闭方正常关闭连接了

以上就是我对 TIME_WAIT 状态的理解

补充:

  • MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机
  • MSL 与 TTL 的区别:MSL 的单位是时间,而 TTL 是经过路由跳数。所以 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被自然消亡
  • TTL 的值一般是 64,Linux 将 MSL 设置为 30 秒,意味着 Linux 认为数据报文经过 64 个路由器的时间不会超过 30 秒,如果超过了,就认为报文已经消失在网络中了
  • TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是:网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。比如:如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 FIN 报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方,一来一去正好 2 个 MSL
  • 可以看到 2MSL时长,这其实是相当于至少允许报文丢失一次。比如:若 ACK 在一个 MSL 内丢失,这样被动方重发的 FIN 会在第 2 个 MSL 内到达,TIME_WAIT 状态的连接可以应对
  • 为什么不是 4 或者 8MSL 的时长呢?你可以想象一个丢包率达到百分之一的糟糕网络,连续两次丢包的概率只有万分之一,这个概率实在是太小了,忽略它比解决它更具性价比
  • 2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。如果在 TIME_WAIT 时间内,因为客户端的 ACK 没有传输到服务端,客户端又接收到了服务端重发的 FIN 报文,那么 2MSL 时间将重新计时。在Linux 系统里 2MSL 默认是 68 秒,那么一个 MSL 也就是 38 秒。Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒

TIME_WAIT 过多有什么危害?

答:

  • 客户端和服务端 TIME_WAIT 过多,造成的影响是不同的
    • 如果客户端(主动发起关闭连接方)的 TIME_WAIT 状态过多,占满了所有端口资源,那么就无法对「目的IP + 目的 PORT」都一样的服务端发起连接了,但是被使用的端口,还是可以继续对另外一个服务端发起连接的
    • 因此,客户端(发起连接方)都是和「目的 IP + 目的 PORT」都一样的服务端建立连接的话,当客户端的 TIME_WAIT 状态连接过多的话,就会受端口资源限制,如果占满了所有端口资源,那么就无法再跟「目的IP + 目的 PORT」都一样的服务端建立连接了
    • 不过,即使是在这种场景下,只要连接的是不同的服务端,端口是可以重复使用的,所以客户端还是可以向其他服务端发起连接的,这是因为内核在定位一个连接的时候,是通过四元组 (源IP、源端口、目的IP、目的端口) 信息来定位的,并不会因为客户端的端口一样,而导致连接冲突。
  • 如果服务端(主动发起关闭连接方)的 TIME_WAIT 状态过多,并不会导致端口资源受限,因为服务端只监听一个端口,而且由于一个四元组唯一确定一个 TCP 连接,因此理论上服务端可以建立很多连接,但是 TCP连接过多,会占用系统资源,比如:文件描述符、内存资源、CPU 资源、线程资源等

补充:

过多的 TIME_WAIT 状态主要的危害有两种:

  1. 第一是占用系统资源,比如文件描述符、内存资源、CPU 资源、线程资源等
  2. 第二是占用端口资源,端口资源也是有限的,一般可以开启的端口为 32768~61000 也可以通过net.ipv4.ip .local_port_range 参数指定范围

客户端和服务端 TIME_WAIT 过多,造成的影响是不同的。所以要从客户端过多 TIME_WAIT 状态和服务端过多 TIME_WAIT 状态来回答


怎么解决 TIME_WAIT 状态过多的问题?

答:

  • 如果是客户端有大量 time_wait 状态,可以考虑开启 tcp_tw_reuse 参数,当发起新连接的时候,会复用处于 time_wait 状态的连接
  • 如果是服务端的话,尽量让主动断开连接的方式,由客户端来进行,可以在应用层设计一个逻辑,当服务端要断开连接的时候,发送一个消息给客户端,客户端收到之后,由客户端来断开 tcp 连接,这样服务端就不会有 time_wait 状态了。

补充:

可以分客户端和服务端来回答

  • 客户端:开启 tcp_tw_reuse 参数,客户端在调用 connect() 函数时,内核会随机找一个 time_wait 状态超过 1 秒的连接给新的连接复用
  • 服务端:服务端不主动断开 tcp 连接,将断开 tcp 连接的主动权交给客户端

服务端产生大量 TIME_WAIT 状态的原因是什么?

答:

主动关闭方才会有 TIME_WAIT 状态,当服务端有大量 TIME_WAIT 状态的连接的时候,代表服务端主动关闭了连接,我觉得可能的原因是:

  • HTTP 没有使用长连接,这时候客户端和服务端都是短连接,服务端发送完 HTTP 响应后,就会主动关闭了连接,如果有大量的短连接过来,那么服务端就会出现大量的 TIME_WAIT 状态,如果是这个问题的话,解决方式就是让客户端和服务端都开启 HTTP Keep-Alive 机制
  • HTTP 长连接的请求数量设置过小,Web 服务端通常会有个参数,来定义一条 HTTP 长连接上最大能处理的请求数量,当超过最大限制时,就会主动关闭连接。比如:Nginx 的 keepalive_requests 这个参数,默认是 100,味着每个 HTTP 长连接最多只能跑 100 次请求,因为当 QPS 请求很高的时候,Nginx 就会频繁的关闭连接,那么此时服务端上就会出大量的 TIME_WAIT 状态。解决的方式也很简单,调大 Nginx 的 keepalive_requests 参数就行

补充:

主动关闭方才会有 TIME_WAIT 状态,所以就要分析服务端为什么会主动关闭连接?

  • 第一个场景:HTTP 没有使用长连接
  • 第二个场景:HTTP 长连接的请求数量达到上限

服务端产生大量 CLOSE_WAIT 状态的原因是什么?

答:

  • 我觉得问题原因在于,是服务端没有及时调用 close 关闭连接的函数,导致出现大量 CLOSE_WAIT 状态的连接,因为只有正确调用了 close 关闭连接函数的时候,TCP 连接状态才会有从 CLOSE_WAIT 状态变为 LAST_ACK 状态
  • 我觉得大概率服务端的代码的问题,这时候我们需要针对具体的代码一步一步的进行排查和定位,主要分析的方向就是服务端为什么没有调用 close

补充:

  • CLOSE_WAIT 状态是「被动关闭方」才会有的状态,而且如果「被动关闭方」没有调用 close 函数关闭连接,那么就无法发出 FIN 报文,从而无法使得 CLOSE_WAIT 状态的连接转变为 LAST_ACK 状态
  • 所以,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接

如果server发送FIN之后,因为client挂掉了,收不到回应,会发生什么?

答:

会触发超时重传机制,重传 FIN 报文,如果 FIN 报文达到最大的重传次数之后,还是没有收到响应,那么server 就会断开链接了

补充:

只要发送的数据没有收到响应,都会触发超时重传,重传达到最大次数之后,就会关闭连接了


如果客户端宕机重启,收到了server 的 FIN,会发生什么?

答:

既然客户端宕机重启了,之前的 TCP 连接信息就不存在了,那么如果收到 server 的 FIN,会回 RST 报文给server,server 收到 RST 报文就会断开连接

补充:

如果 TCP 连接信息没有了,那么再次收到该 TCP 连接的报文,就会回 RST 报文


TCP 与 UDP


TCP 和 UDP 有什么区别?

答:

我觉得主要有这几个方面的区别:

  • TCP 是面向连接的协议,在发送数据的时候,需要先建立 TCP 三次握手,而 UDP 无连接的协议,直接就可以发送数据
  • TCP 会通过超时重传、流量控制、拥塞控制保证数据的可靠传输,而 UDP 并没有这些特性,UDP 不考虑数据的可靠性
  • TCP 发送的数据是以字节流的形式,没有边界。而 UDP 是一个包一个包的发送,是有边界的

所以,综合来看:

  • TCP 的优势在于可以保证数据的可靠性,但是缺陷就是实时性没有 UDP 协议好
  • UDP 的优势在于足够简单,不用建立连接,数据直接丢过去即可,并且 UDP 包头比 TCP 包头小很多

所以 UDP 实时性和速度方面是比 TCP 好的

补充:

  • 可以从几个角度分析:连接、可靠性、传输方式
  • 最后总结,这两个协议的优劣势

详细链接:TCP vs UDP——哪个协议更快?


什么时候用 TCP?什么时候用 UDP?

答:

  • 如果主要关注数据接收的可靠性和顺序,可以选使用 TCP,比如:FTP协议、HTTP协议都是基于 TCP 协议进行传输数据
  • 如果主要关注的是速度和实时性,而且并不在意某些数据包的丢失,可以选使用 UDP 协议,比如:直播视频会议场景

补充:

UDP 和 TCP 应用场景:

  • TCP 传输速度慢,但是数据传输可靠性高
  • UDP 传输速度快,但是不保证传输的可靠性

TCP vs UDP


此时此刻的视频面试用的 UDP 还是 TCP?UDP丢包会有什么现象?

答:

我觉得是 UDP 协议,因为视频会议这个场景下,重要的是实时性,UDP 协议实时性比 TCP 好,采用 UDP 协议传输音视频数据的话,如果发生了丢包,只是就丢失某一瞬间的画面和语音,然后还可以继续进行会议沟通,不会太影响视频会议的体验,如果是采用 TCP 协议的,由于 TCP 是可靠传输,如果发生了丢包,可能画面就卡住不动,等丢包重传才会推进画面,这样实时性就比较差了

详细链接:[34 UDP 协议:UDP 和 TCP 相比快在哪里?](https://learn.lianglianglee.com/专栏/重学操作系统-完/34 UDP 协议:UDP 和 TCP 相比快在哪里?.md)


UDP 怎么改造变为可靠传输?

答:

  • 我会在应用层增加序列号字段,用来确保 UDP 的数据可以按序接收,同时还会增加确认号,用来实现超时重传机制,当超过一定时间内没收到已发送数据的确认号,就重传该数据包
  • 我还会在应用层开辟一个缓冲区,用来实现滑动窗口,有了滑动窗口这样发送数据可以先批量发送数据,不需要等上一个数据的确认了才能发送,提高了发送速率,同时还可以基于滑动窗口实现流量控制,用来保证发送方能按接收方的接收能力发送数据,避免发送的数据对方接收不了而发生数据丢失
  • 最后,为了保证整个网络的带宽环境,还需要实现拥塞控制,确保发送方的数据,不会占满整个带宽
  • 我觉得 UDP 实现可靠传输相比 TCP 可靠传输有几点优势:
    1. 拥塞控制算法可以根据不同的应用选用不同的拥塞控制算法,而 TCP 选用拥塞控制算法的时候,是所有应用都使用这一套拥塞控制算法
    2. 升级方便,TCP 是在内核实现的,升级 TCP 需要升级操作系统,而 UDP 可靠传输是在应用层实现的,升级协议就像升级软件一样简单
    3. 可以实现网络连接迁移,在应用层用连接id来唯一标识一个连接,不必像 TCP 那样,是通过四元组才确定连接的,只要四元组的信息发生了变化,就需要重新建立连接

补充:

按照 TCP 协议怎么实现可靠传输的方式,在应用层实现一遍就好了,最后可以补充说明基于 UDP 协议实现的可靠传输相比于 TCP 有什么优势


TCP 和 UDP 可以共用一个端口吗?

答:

  • 可以的
  • socket 是根据五元组信息唯一确认的:协议类型、源 ip 地址、源端口、目标 ip 地址、目标端口,只要有一个信息不同,就会认为是不同的 socket,不会引起冲突,所以 TCP 和 UDP 是可以共用一个端口号的

补充:

  • 在数据链路层中,通过 MAC 地址来寻找局域网中的主机。在网际层中,通过 IP 地址来寻找网络中互连的主机或路由器。在传输层中,需要通过端口进行寻址,来识别同一计算机中同时通信的不同应用程序

  • 所以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包

  • 传输层有两个传输协议分别是 TCP 和 UDP,在内核中是两个完全独立的软件模块。当主机收到数据包后,可以在 IP 包头的「协议号」字段知道该数据包是 TCP/UDP,所以可以根据这个信息确定送给哪个模块(TCP/UDP)处理,送给 TCP/UDP 模块的报文根据「端口号」确定送给哪个应用程序处理

    TCP、UDP公用一个端口号

  • 因此, TCP/UDP 各自的端口号也相互独立,如:TCP 有一个 80 号端口,UDP 也可以有一个 80 号端口,二者并不冲突

详细链接:4.18 TCP 和 UDP 可以使用同一个端口吗? | 小林coding


TCP 可靠性


TCP 是如何保证可靠性的?

答:

  • 连接建立:TCP 建立连接的时候,需要三次握手,这个过程可以证明双方都具有发送和接收的能力,并且能避免历史连接的建立
  • 序列号与确认应答:TCP 头部有序列字段,可以保证数据的有序性,还有确认号,用来确认收到了数据
  • 数据包重传:如果发送方发送的数据,长时间没有收到确认报文,就会触发超时重传,重传丢失的报文
  • 滑动窗口机制:TCP 有流量控制的机制,发送方会根据接收方的接收窗口来发送数据报文,可以避免发送方发送的数据报文太大,导致接收方接收不了而丢包的问题
  • 拥塞控制:TCP 有拥塞控制的机制, 通过慢启动、拥塞避免、拥塞发生,快速重传和快速恢复等算法调整发送速率来避免网络拥塞。当网络出现拥塞时,TCP 会降低发送速率,以减少网络负载,保证数据的可靠传输

补充:

从 连接建立、序列号与确认应答、数据包重传、滑动窗口机制、拥塞控制 方面回答

详细链接:4.2 TCP 重传、滑动窗口、流量控制、拥塞控制 | 小林coding


TCP 流量控制和拥塞控制的区别?

答:

这两个机制都是 TCP 协议实现可靠传输的因素,主要区别在于:

  • 流量控制:这是一个端到端的控制机制,目的是防止发送方发送的数据过快,导致接收方处理不过来。这通过滑动窗口机制实现,接收方在 ACK 报文中告诉发送方自己的接收窗口大小,这样就告诉了发送方可以接收的最大数据量
  • 拥塞控制:这是一个网络层面的控制机制,目的是防止过多的数据包同时在网络中传输,导致网络拥塞,主要是通过慢启动、拥塞避免、拥塞发生,快速重传和快速恢复,这几种算法实现的

所以,流量控制关注的是保护接收方不被淹没,而拥塞控制关注的是保护网络不被过载


滑动窗口怎么设计的?解决什么问题?

答:

发送方和接收方在内核各自都有一个缓冲区,发送缓冲区和接收缓冲区上都各有一个窗口,发送方的窗口表示可发送的最大数据量,接收方的窗口表示可接收的最大数据量:

  • 发送方有了发送窗口后,那么发送方可以不用等待已发送数据的确认报文,就可以继续发送下一批数据,提高了发送的速率
  • 接收方有了接收窗口后,可以实现流量控制,把接收方的接收窗口告诉给发送方,让发送方按自己的接收情况来发送数据,避免发送方发送的数据过快,导致接收方处理不过来

TCP 协议拥塞控制怎么实现的?

答:

  • TCP协议的拥塞控制主要通过五个算法来实现:慢启动、拥塞避免、超时重传、快速重传 和 快速恢复
    • 慢启动:发送方开始时设置一个较小的拥塞窗口大小,在每收到一个对新的报文段的确认后,每当成功发送跟拥塞窗口大小等量的数据后,拥塞窗口大小就会翻倍,以指数方式增长,直到拥塞控制窗口达到慢启动门限
    • 拥塞避免:当窗口大小达到慢启动门限后,就进入拥塞避免阶段,每当成功发送跟拥塞窗口大小等量的数据后,拥塞窗口大小就会增加一个报文段的大小,以线性方式增长
    • 拥塞发生:随着发送速率慢慢增长,可能网络会出现拥塞,发生了数据包丢失,这时候就需要重传数据重传机制主要有两种,一个是超时重传和快速重传
    • 超时重传:当发生了超时重传,慢启动门限会设置为拥塞窗口的一半,并且将拥塞窗口恢复为初始值,接着就重新开始慢启动,发送速率就会瞬间下降了很多
    • 快速重传和快速恢复:当发送方连续收到三个重复确认时,就认为发生了丢包,这时候拥塞窗口会减少到原来的一半,然后慢启动门限设置为减少后的拥塞窗口大小,然后进入到快速恢复阶段,这时候会把拥塞控制窗口+3,3 的意思是确认有 3 个数据包被收到了,然后重传丢失的报文,如果收到重传丢失报文的 ACK 后,将拥塞窗口设置为慢启动门限,这样就直接进入拥塞避免,继续增大发送速率
  • 这些拥塞控制算法,可以让 TCP 协议能够根据网络状况动态调整发送速率,避免因为过大的流量导致网络拥赛

补充:

慢启动 → 拥塞避免 → 超时重传 → 慢启动:

慢启动 → 拥塞避免 → 超时重传 → 慢启动

慢启动 → 拥塞避免 → 快速重传 → 快速恢复 → 拥塞避免:

慢启动 → 拥塞避免 → 快速重传 → 快速恢复 → 拥塞避免


TCP 的延迟应答和累计应答是什么?

答:

  • TCP 的延迟应答 是指接收方不立即发送 ACK确认接收到的数据,而是延迟一段时间后再发送 ACK。这样可以等待是否有更多的数据要发送,从而减少 ACK 报文的数量,提高网络利用率
  • TCP 的累计应答 是指接收方可以一次性确认接收到多个连续的数据包,而不是每收到一个数据包就发送一个 ACK。这样可以减少 ACK 报文的数量,提高网络效率

补充:

延迟应答:TCP 在接收到对端的报文后并不会立即发送 ACK,而是等待一段时间发送 ACK,以便将 ACK 和要发送的数据一块发送,好处是能减少 ACK 报文的数量,提高网络利用率。延迟时间不能无限延长,否则对方端会认为丢包超时而造成超时重传。Linux 采用动态调节算法来确定等待的时间。延迟应答如下图:

TCP延迟应答

累计应答:接收方可以一次性确认接收到多个连续的数据包,而不是每收到一个数据包就发送一个 ACK。这样可以减少 ACK 报文的数量,提高网络效率。累计应答如下图:

TCP累计应答


TCP 场景问题


TCP 拆包沾包原因是什么?怎么解决?

答:

  • 我的理解 TCP 是一个面向字节流协议,并不关心数据包的边界
    • 如果发送的数据包超过 MSS 大小或者接收窗口大小后,会被拆分多个 TCP 段发送,这时候站在应用层的角度,就是一个完整的数据包被拆开了
    • 如果发送的数据包太小,TCP 还有一个 Nagle 算法,会把多个小数据包堆积成一个 TCP 段发送,这时候就会感觉数据包是粘合一起发送的
  • 其实我认为,TCP 拆包沾包并不是 TCP 的问题,只是因为 TCP 的特性,才出现的现象,所以要解决拆包和沾包,主要是在应用层进行处理的,比方说有这些解决方案:
    • 固定消息长度的方式,每个数据报文都需要一个固定的长度。当接收方累计读取到固定长度的报文后,就认为已经获得一个完整的消息。当发送方的数据小于固定长度时,则需要空位补齐。但是缺点也非常明显,无法很好设定固定长度的值,如果长度太大会造成字节浪费,长度太小又会影响消息传输,所以在一般情况下消息定长法不会被采用
    • 特定分隔符的方式,可以在每次发送报文的尾部加上特定分隔符,接收方就可以根据特殊分隔符进行消息拆分。比方说,HTTP 请求报文就是通过空白行的方式,分隔了请求头和请求体。这种方案需要注意的是分隔符的选择一定要避免和消息体中字符相同,以免冲突
    • 消息长度 + 消息内容的方式,消息头中存放消息的总长度,例如:使用 4 字节的 int 值记录消息的长度,消息体实际的二进制的字节数据。接收方在解析数据时,首先读取消息头的长度字段 Len,然后紧接着读取长度为 Len 的字节数据,该数据即判定为一个完整的数据报文,这个方案项目开发中最常用的一种方法,因为使用方式非常灵活,且不会存在消息定长法和特定分隔符法的明显缺陷。当然在消息头中不仅只限于存放消息的长度,而且可以自定义其他必要的扩展字段,例如:消息版本、算法类型等

详细链接:[06 粘包拆包问题:如何获取一个完整的网络包?](https://learn.lianglianglee.com/专栏/Netty 核心原理剖析与 RPC 实践-完/06 粘包拆包问题:如何获取一个完整的网络包?.md)


TCP 的 keepalive 了解吗?说一说它和 HTTP 的 keepalive 的区别?

答:

  • HTTP 的 Keep-Alive 是叫 HTTP 长连接,该功能是由应用程序实现的,可以使得用同一个 TCP 连接来发送和接收多个 HTTP 请求和应答,减少了 HTTP 短连接带来的多次 TCP 连接建立和释放的开销
  • TCP 的 Keepalive 是叫 TCP 保活机制,该功能是由内核实现的,当客户端和服务端双方长达一定时间没有进行数据交互时,内核为了确保该连接是否还有效,就会发送探测报文,来检测对方是否还在线,然后来决定是否要关闭该连接

补充:

实现的层面不同:

  • HTTP 的 Keep-Alive,是由应用层(用户态)实现的,称为 HTTP 长连接
  • TCP 的 Keepalive,是由 TCP 层(内核态)实现的,称为 TCP 保活机制

详细链接:4.15 TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗? | 小林coding


MTU是啥?MSS是啥?

答:

MTU 是一个网络包的最大长度,一般是 1500 字节,MSS 是除去 IP 包和 TCP 包的数据的最大长度,IP 层如果超过 MTU 大小就会分片,TCP 如果有超过 MSS的应用数据就要分段

补充:

MTU vs MSS

  • MTU:一个网络包的最大长度,以太网中一般为 1500 字节。当 IP 层有一个超过 MTU 大小的数据要发送,那么 IP 层就要进行分片,把数据分片成若干片,保证每一个分片都小于 MTU
  • MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度。当 TCP 层有一个超过MSS 大小的应用数据,那么 TCP 层就要针对应用层数据进行分片,把数据分片成若干片,保证每一个分片都小于 MSS

IP层会分片,为什么TCP层还需要MSS呢?

答:

  • 如果交给 IP 来进行分片,如果某一个 IP 分片丢失了,整个 IP 报文的所有分片都得重传。因为 IP 层本身没有超时重传机制,它由传输层的 TCP 来负责超时和重传
  • 当某一个 IP 分片丢失后,接收方的 IP 层就无法组装成一个完整的 TCP 报文(头部 + 数据),也就无法将数据报文送到 TCP 层,所以接收方不会响应 ACK 给发送方,因为发送方迟迟收不到 ACK 确认报文,所以会触发超时重传,就会重发整个 TCP 报文(头部 +数据)
  • 应用层的数据在 TCP 层经过 MSS 分片之后,每一个分片都具备 TCP 头部信息,这样经过 MSS 分片后的报文,如果某一个丢失了,只需要重传这一个丢失的 TCP 报文就可以了,而不用重传所有的分片,大大增加了重传的效率

补充:

  • 当 IP 层有一个超过 MTU 大小的数据(IP头部 + TCP 头部 + TCP 数据)要发送,那么 IP 层就要进行分片,把数据分片成若干片,保证每一个分片都小于 MTU。把一份 IP 数据报进行分片以后,由目标主机的 IP 层来进行重新组装后,再交给上一层 TCP 传输层
  • 这看起来井然有序,但这存在隐患的,那么当如果一个 IP 分片丢失,整个 IP 报文的所有分片都得重传,因为 IP 层本身没有超时重传机制,它由传输层的 TCP 来负责超时和重传。当某一个 IP 分片丢失后,接收方的 IP 层就无法组装成一个完整的 TCP 报文(头部 + 数据),也就无法将数据报文送到 TCP 层,所以接收方不会响应 ACK 给发送方,因为发送方迟迟收不到 ACK 确认报文,所以会触发超时重传,就会重发「整个 TCP 报文(头部 +数据)」
  • 因此,可以得知由 IP 层进行分片传输,是非常没有效率的所以,为了达到最佳的传输效能 TCP 协议在建立连接的时候通常要协商双方的 MSS 值,当 TCP 层发现数据超过 MSS 时,则就先会进行分片,当然由它形成的 IP 包的长度也就不会大于 MTU ,自然也就不用 IP 分片了
  • 经过 TCP 层分片后,如果一个 TCP 分片丢失后,进行重发时也是以 MSS 为单位,而不用重传所有的分片,大大增加了重传的效率

一个服务端进程最多可以建立多少条 TCP 连接?

答:

  • 一条 TCP 连接是通过 源IP地址、目的IP地址、源端口、目的端口 这四个信息唯一确定的。服务端进程通常是会固定监听一个端口,等待客户端的连接请求,现在假设服务端的 IP 地址和 端口号 都是不变,那么 一个服务端进程最大能支持的理论连接数 等于 客户端的 IP 数量 * 客户端的端口数量,也就是 2 的 48 次方个连接数量
  • 这个只是一个理论值,实际上服务端还会受系统资源的限制,比如:文件描述符的最大数量、CPU和内存资源

补充:

  • TCP 是通过 四元组 唯一确认一条 TCP 连接的

    TCP四元组

  • 源 IP 地址和目的 IP 地址的字段(32 位)是在 IP 头部中,作用是定位网络中的主机。源端口和目的端口的字段(16 位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。服务端通常固定在某个本地端口上监听,等待客户端的连接请求。比如:我网站的服务端是 nginx,监听了 80 端口

    我网站的服务端是 nginx,监听了 `80` 端口

  • 那么假设服务端的 IP 地址和端口号不变,客户端 IP 和端口是可变的,一个服务端进程最大能支持的理论连接数:*一个服务端进程最大能支持的理论连接数 = 客户端的 IP 数量 客户端的端口数量

  • 对 IPv4,客户端的 IP 数最多为 2 的 32 次方,客户端的端口数最多为 2 的 16 次方,也就是一个服务端进程最大能支持的理论连接数为 2 的 48 次方

  • 实际上服务端最大并发 TCP 连接数远不能达到理论上限,会受以下因素影响:

  • 文件描述符限制,每个 TCP 连接都是一个文件,如果文件描述符被占满了,会发生 Too many open files。Linux 对可打开的文件描述符的数量分别作了三个方面的限制:

    • 系统级:当前系统可打开的最大数量,通过 cat /proc/sys/fs/file-max 查看
    • 用户级:指定用户可打开的最大数量,通过 cat /etc/security/limits.conf 查看
    • 进程级:单个进程可打开的最大数量,通过 cat /proc/sys/fs/nr_open 查看
  • 内存限制,每个 TCP 连接都要占用一定内存,操作系统的内存是有限的,如果内存资源被占满后,会发生 OOM

详细链接:腾讯三面:一台服务器,最大支持的TCP连接数是多少?


一个机器最多可以建立多少条 TCP 连接?

答:

  • 一条 TCP 连接是由四元组组成的,服务器设备上可以有多个进程监听多个端口,然后如果服务器所有端口都被用来监听的话,理论上最大可以建立的 TCP 连接数 等于 客户端 IP数 x 客户端端口数 x 服务端端口数,也就是 2^32 x 2^16 x 2^16
  • 上面这个只是理论值,实际中由于服务器硬件资源的限制是无法达到的,比如:内存资源的限制,我之前了解到每一条静止的 TCP 连接内存占用大概 3.3K,如果服务器的物理内存是 4G,那么最大只能建立 100 万左右(4GB/3.3KB)的连接了

详细链接:漫画 | 一台Linux服务器最多能支撑多少个TCP连接?、漫画 | 花了七天时间测试,我彻底搞明白了 TCP 的这些内存开销! - 知乎


如果已经建立了连接,但是服务端突然出现断电了会发生什么?

答:

服务端突然断电的后:

  • 如果客户端接下来会发送数据,那么由于服务端断电了,客户端已发送的数据就没办法得到确认,于是就会发生超时重传,重传次数达到上限之后,客户端就会断开 TCP 连接了
  • 如果客户端接下来不会再发送数据,那么要看客户端有没有开启 TCP 保活机制:
    • 如果没有开启的话,客户端的 TCP 状态将一直保持不变
    • 如果有开启了 TCP 保活机制,双方超过一段时间没有进行数据交互的话,内核就会触发 TCP 保活机制,定时发送探测报文,因为服务端断电了,客户端发送的探测报文,都不会得到响应,那么探测次数达到上限,还未收到响应的话,客户端就会断开 TCP 连接了

补充:

分情况讨论:

  • 客户端会发送数据的情况
  • 客户端不会发送数据的情况
    • 客户端没有开启 TCP 保活机制的情况
    • 客户端有开启 TCP 保活机制的情况

详细链接:4.12 TCP 连接,一端断电和进程崩溃有什么区别? | 小林coding


如果已经建立了连接,但是服务端的进程崩溃会发生什么?

答:

服务端进程崩溃的话,内核会负责回收服务端进程的资源,会发送 FIN 报文,和客户端进行四次挥手断开连接

补充:

TCP 的连接信息是由内核维护的,所以当服务端的进程崩溃后,内核需要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不需要进程的参与,所以即使服务端的进程退出了,还是能与客户端完成 TCP 四次挥手的过程


TCP 中 SYN 洪水是什么?如何防止?

答:

  • SYN 洪水攻击就是攻击者伪造大量不同 IP 地址的 SYN 报文发送给服务端,服务端每收到 SYN 报文后,会把还没完成连接建立的 socket,存放在 tcp 半连接队列,然后响应 syn-ack 报文,但是这些 IP 地址都是不存在的,这样服务端就无法收到第三次握手,这样就会导致 tcp 半连接队列被占满了,占满后,服务端就无法再建立 tcp 连接了,不能给正常的用户提供服务了
  • 解决的方式,我觉得最好的是开启 tcp 的 syn_cookie 机制,它可以在服务端第二次握手的时候,生成一个伪随机的序列号,用于验证客户端的 SYN 包。只有在客户端回应服务器的 ACK 包时,服务器才会分配资源,所以可以在不使用 SYN 半连接队列的情况下成功建立连接,相当于绕过了 SYN 半连接来建立连接。其次的话,可以通过调整内核参数来增大半连接队列的大小,以及减少 syn+ack 重传的次数来避免 SYN 洪水攻击

补充:

TCP 连接建立是需要三次握手,假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个报文,就进入 SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的 TCP 半连接队列,使得服务端不能为正常用户服务

SYN洪水

解决方式:

  • 开启 tcp_syncookies 功能,开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接,相当于绕过了 SYN 半连接来建立连接
  • 增大半连接队列,通过增大 net.ipv4.tcp_max_syn_backlog,增大 listen() 函数中的 backlog,增大net.core.somaxconn,这三个参数来增大半连接队列
  • 通过减少 tcp_synack _retries 参数来减少 SYN+ACK 重传次数,当服务端受到 SYN 攻击时,就会有大量处于 SYN_RECV 状态的 TCP 连接,处于这个状态的 TCP 会重传 SYN+ACK,当重传超过次数达到上限后,就会断开连接。那么针对 SYN 攻击的场景,我们可以减少 SYN+ACK 的重传次数,以加快处于 SYN_RECV 状态的 TCP 连接断开

详细链接:SYN 洪水 DDoS 攻击 | Cloudflare


网络层


ping 的工作原理说一下?

答:

ping 是通过 ICMP 协议来实现的,ping 的时候,会发送类型为回送请求的 ICMP 报文,对方接收到之后,就会回复类型为回送应答的 ICMP 报文

补充:

ping一下会发生什么?

ping 命令是用来探测目标 ip 地址是否可以访问:

ping命令

  • ping 命令执行的时候,源主机首先会构建一个 ICMP 回送请求消息数据包,由 ICMP 协议将这个数据包连同服务端 IP 一起交给 IP 层,IP 层将以服务端 IP 作为目的地址,本机 IP 地址作为源地址,协议字段设置为 1,再加上一些其他控制信息,构建一个 IP 数据包;然后加入MAC头;如果在本地 ARP 映射表中查找出服务端 IP 所对应的 MAC 地址,则可以直接使用,如果没有,则需要发送 ARP 协议查询 MAC 地址。获得 MAC 地址后,由数据链路层构建一个数据帧,目的地址是 IP 层传过来的 MAC 地址,源地址则是本机的 MAC 地址;还要附加上一些控制信息,依据以太网的介质访问规则将它们传送出去
  • 目的收到这个数据帧后,先检查它的目的 MAC 地址,并和本机的 MAC 地址对比,如符合,则接收,否则就丢弃。接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层。IP 层检查后,将有用的信息提取后交给 ICMP 协议。主机 B 会构建一个 ICMP 回送响应消息数据包,回送响应数据包的类型字段为 0,序号为接收到的请求数据包中的序号,然后再发送出去给主机A
  • 在规定的时间内,源主机如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 回送响应消息,则说明目标主机可达

详细链接:5.2 ping 的工作原理 | 小林coding


交换机和路由器有什么区别?

答:

  • 交换机工作在 MAC 层,称为二层网络设备,主要处理数据帧的转发和交换,交换机会根据 MAC 地址来转发数据包,实现局域网内设备之间的通信
  • 路由器工作在 IP 层,称为三层网络设备,主要负责 IP 数据包的转发和路由选择,路由器会根据 IP 地址来转发数据包,实现不同网络之间的通信

补充:

  1. 网络层级不一样
  2. 功能不一样

什么是 IP 地址?

答:

IP 地址是用于在计算机网络上唯一标识和定位网络中的设备,IP 地址允许计算机在网络上相互通信和交换数据,在 TCP/IP 协议中,IP 地址与 MAC 地址结合使用,实现了设备之间的通信和数据传输

补充:

  • IP 地址是用于在网络中唯一标识和定位设备的一种地址,IP 地址是网络层协议中使用的一种地址,它分为IPv4地址和IPv6地址两种类型
    1. IPv4地址:IPv4地址是 32 位的二进制地址,通常用点分十进制表示,如:192.168.1.1。IPv4地址由四个8位字节组成,每个字节范围从0到255之间,共计可表示约42亿个不同的地址。然而,由于IPv4地址资源有限,目前已经出现了地址枯竭的问题
    2. IPv6地址:为了解决IPv4地址资源枯竭的问题,IPv6地址被引入并取代了IPv4地址。IPv6地址是 128 位的地址,采用冒号分隔的八组十六进制数表示,如:2001:0db8:85a3:0000:0000:8a2e:0370:7334。IPv6 地址提供了极其庞大的地址空间,理论上可以支持几乎无限数量的设备连接到互联网
  • IP地址的作用是在互联网上唯一标识一个设备或主机,使得数据包能够准确地被发送到目的地。在TCP/IP 协议中,IP 地址与 MAC 地址结合使用,实现了设备之间的通信和数据传输

什么是 mac 地址?

答:

MAC 地址是在数据链路层中使用的标识符,只在局域网范围内有效。在互联网通信中,数据包最终是通过 IP 地址来路由和传递的,而在局域网中则是通过 MAC 地址来实现设备之间的直接通信。MAC 地址与 IP 地址结合起来,共同协助实现了数据在网络中的正确传输和交换

补充:

  • MAC 地址是网络设备在数据链路层中使用的物理地址,用于唯一标识网络设备。每个网络设备都有一个唯一的 MAC 地址,通常由 48 位二进制数表示,分为 6 个十六进制数对,用冒号或短线分隔,如:00:1A:2B:3C:4D:5E
  • MAC 地址主要用于通过局域网传输数据时,帮助网络设备进行识别和寻址。与 IP 地址不同,MAC 地址是固定的且与硬件设备绑定,不会因为设备连接到不同网络而改变。当数据包在局域网内传输时,源设备将目标设备的 MAC 地址作为目标地址写入数据包头部,以确保数据包能够准确地从发送者传输到接收者
  • 需要注意的是,MAC 地址是在数据链路层中使用的标识符,只在局域网范围内有效。在互联网通信中,数据包最终是通过 IP 地址来路由和传递的,而在局域网中则是通过 MAC 地址来实现设备之间的直接通信。MAC 地址与 IP 地址结合起来,共同协助实现了数据在网络中的正确传输和交换

IP地址和MAC地址有什么区别?

答:

  • IP 地址用于在 网络中 唯一标识和定位设备,它是在网络层使用的地址,用于实现不同网络之间的通信
  • MAC 地址用于在 局域网中 唯一标识和定位设备,它是在数据链路层使用的地址,用于实现局域网内设备之间的通信

详细链接:2.2 键入网址到网页显示,期间发生了什么? | 小林coding、3.7 MAC地址、IP地址以及ARP协议(1) — MAC地址_哔哩哔哩_bilibili


为什么有了IP地址,还需要MAC地址?

答:

  • 只有 MAC,没有 IP,网卡的实现上极其困难。如果只使用 MAC 地址的话,路由器就需要记住每个 MAC 地址所在的子网是哪一个,而世界上有 2 的 48 次方个 MAC 地址,这就意味着即使我们给每个 MAC 地址只留 1 字节的储存空间,每个路由器也需要 256 TB 的内存,这显然是不可能实现的
  • 只有 IP,没有 MAC,IP 地址的局限。IP 地址是要设备上线以后,才能根据他进入了哪个子网来分配的,在设备还没有 IP 地址的时候(或者分配 IP 地址的过程中),还需要用 MAC 地址来区分不同的设备,并根据 MAC 地址通信

补充:

可以从只有 mac 没有 ip 会有什么问题,只有 ip 没有 mac 会有什么问题来回答


NAT是什么协议?

答:

  • NAT 协议在网络层工作,会将私有 IP 地址转换为公网 IP 地址,这样可以实现局域网的设备与互联网其他设备的通信
  • NAT 协议比较常见的转换操作是端口转换,多个私有 IP 地址可以共享一个公网 IP 地址,通过端口来区分不同的私有 IP 地址。所以,NAT 协议的优势在于可以节省公共 IP 地址资源,因为多个内部设备可以共享同一个公共 IP 地址

补充:

  • 图中有两个客户端 192.168.1.10 和 192.168.1.11 同时与服务器 183.232.231.172 进行通信,并且这两个客户端的本地端口都是 1025
  • 此时,两个私有 IP 地址都转换 IP 地址为公有地址 120.229.175.121,但是以不同的端口号作为区分。于是,生成一个 NAPT 路由器的转换表,就可以正确地转换地址跟端口的组合,令客户端 A、B 能同时与服务器之间进行通信

NAT地址转换


192.168.1.100/24 中的斜杠代表什么意思?

答:

  • 斜杠(/)后面的数字表示子网掩码的位数
    • 比如:192.168.1.100/24 中的斜杠后面的数字 24 表示子网掩码的位数,子网掩码用于划分 IP 地址中的网络部分和主机部分。将子网掩码和 IP 地址进行 与 运算,就可以得到网络号
    • 具体来说,192.168.1.100/24 表示前 24 位是网络部分,后 8 位是主机部分

补充:

  • 主要关注网络号和主机号的概念,

  • a.b.c.d/x,其中 /x 表示前 x 位属于网络号,x 的范围是 0 ~ 32 比如:10.100.122.2/24,这种地址表示形式就是 CIDR,/24 表示前 24 位是网络号,剩余的 8 位是主机号

    10.100.122.2/24

    • 还有另一种划分网络号与主机号形式,那就是子网掩码,掩码的意思就是掩盖掉主机号,剩余的就是网络号

    • 将子网掩码和 IP 地址按位计算 AND,就可得到网络号

      将子网掩码和IP地址按位计算AND


网络攻击问题


DNS 劫持是什么?

答:

当我们访问网站的时候, 实际上是会先进行域名解析得到网站服务器的 IP 地址,然后才进行后续的访问。DNS 劫持利用了这个过程中的漏洞,攻击者在 DNS 服务器上篡改 DNS 解析结果,将域名解析到攻击者控制的恶意服务器上,这时候我们访问的域名就被重定向到恶意网站上

补充:

DNS 劫持就是黑客劫持了 DNS 服务器,篡改了 DNS 解析结果,将 client 请求的域名解析到错误的 IP 地址上,让真实服务器拿不到请求,更多发生在诱导、钓鱼、广告植入、诈骗等诸多场景

DNS劫持

  • 解决办法:手动更换公共 DNS 服务器,绕过被劫持的 DNS 服务器

详细链接:【硬核科普】能上QQ但是打不开网页?详解DNS服务,DNS解析,DNS劫持和污染_哔哩哔哩_bilibili


DNS 污染是什么?

答:

DNS 污染就是得到了一个虚假的结果,攻击者监听 DNS 查询,一旦发现查询的域名与自己是匹配的,就把自己伪装成目标域名服务器,然后返回虚假的结果给用户,这样用户域名解析的结果就是错误的,无法和正确的目标服务器 IP 进行通信

补充:

DNS 污染是一种让一般用户由于得到虚假目标主机 IP 而不能与其通信的方法,是一种 DNS 缓存投毒攻击(DNS cache poisoning)

  • 工作方式是:由于通常的 DNS 查询没有任何认证机制,而且 DNS 查询通常基于的 UDP 是 无连接不可靠 的协议,因此 DNS 的查询非常容易被篡改,通过对 UDP 端口 53 上的 DNS 查询进行入侵检测,一经发现与关键词相匹配的请求则立即伪装成目标域名的解析服务器(NS,Name Server)给查询者 返回虚假结果

DNS污染

  • DNS 污染症状:目前一些在被禁止访问的网站基本都是通过 DNS 污染来实现的,例如:YouTube、facebook 等网站
  • 解决办法:
    1. 绕过被污染的非权威 DNS 服务器,直接访问干净的公共 DNS 服务器
    2. 在本机直接绑定 hosts,绕过 DNS 解析过程(但由于 IP 地址会变更,故本机的 hosts 也需要不断更新)

详细链接:DNS污染和DNS劫持 - 简书


简述 DDOS 攻击原理,如何防范它?

答:

  • DDOS 攻击就是用大量的僵尸计算机对服务器发送大量的请求,让服务器的带宽、CPU和内存耗尽,让服务器超载后,无法再对外提供正常的服务
  • DDOS 攻击大体分为网络层攻击和应用层攻击,攻击应用层的方式比如有:DNS 洪水攻击,攻击传输层的方式比如有:SYN 洪水攻击、UDP 洪水攻击。
  • 我觉得可以通过这几个方面防御 DDOS 攻击:
    1. 限制单个 IP 地址的请求频率,并且对异常流量的 IP 地址,拉黑名单,配置防火墙规则,阻止恶意流量请求
    2. 增加用户验证机制,使用验证码、人脸识别等方式,增加用户验证的难度,减少恶意请求的影响
    3. 花钱买可靠的 DDoS 防护服务提供商,他们具备强大的网络基础设施和专业的防护技术,能够识别和过滤掉恶意流量,确保正常的服务运行

详细链接:DDoS技术鉴赏_哔哩哔哩_bilibili


什么是 XSS 攻击?如何防止?

答:

  • XSS 攻击叫 跨站点脚本攻击, 攻击方式是攻击者在一些可以评论或者发帖的网站,发布一些恶意脚本代码,然后被服务端保存了,后面访问的网站的时候,浏览器会执行了该恶意脚本,这样攻击者就可以窃取用户的敏感信息了
  • 要防止 XSS 攻击的话,可以通过这些方式:
    1. 输入验证和过滤:过滤一些特殊的字符,比如:javascript 脚本中的 <> 进行转移 <> 再进行存储,这样就能有效的进行 xss 攻击的预防
    2. 使用 HTTP-only Cookie:将敏感信息存储在 HTTP-only Cookie 中,限制 JavaScript 的访问权限,防止恶意脚本窃取用户的 Cookie 信息

补充:

  • 存储型 XSS 攻击又称为持久性跨站点脚本攻击,通常攻击者将代码存储到漏洞服务器中,用户浏览相关页面发起攻击
  • 攻击步骤:
    1. 攻击者将恶意脚本代码上传或存储到漏洞服务器
    2. 服务器把恶意脚本保存到服务器
    3. 当正常客户访问服务器时,服务器会读取恶意数据并且直接使用
    4. 服务器会返回含有恶意脚本的页面
  • 实际案例:
    • 譬如发帖中发出包含恶意代码的内容,其他内容访问到该内容后,满足特定条件后条件即触发
    • 需要后台不过滤信息,并且前端展示时也不过滤信息
  • 注意:这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等

详细链接:XSS 跨站脚本攻击 - JavaScript Guidebook


什么是 CSRF 攻击?如何防止?

答:

  • CSRF 叫 跨站点请求伪造攻击,攻击形式是:用户先登录银行 A 网站,这时候就获得了 A 网站的Cookie,然后不小心访问了一个恶意 B 网站,B 网站会让用户向银行 A 网站发起一个转账请求,由于用户端有了银行 A 网站的 Cookie,这时候有可能就会转账成功,造成并非本人意愿的操作结果
  • 防御 CSRF 攻击的话,可以有这些方式:
    1. 同源检测:在服务器端对请求进行同源检测,只接受来自同一域名下的请求。这可以通过检查请求头中的 Referer 字段或者 Origin 字段来实现
    2. 使用验证码:对于敏感操作,要求用户输入验证码进行验证,以防止自动化脚本发起的恶意请求
    3. 使用 CSRF 令牌:在用户执行敏感操作时,要求用户提交一个 CSRF 令牌。该令牌是一个随机生成的字符串,存储在用户的会话中,并且在每个请求中都要验证该令牌的有效性。攻击者无法伪造正确的 CSRF 令牌,从而防止 CSRF 攻击

补充:

  • CSRF 叫 跨站点请求伪造攻击,攻击者通过跨站请求,以合法的用户身份进行非法操作如转账交易、发表评论等。其核心是利用了浏览器 Cookie 或服务器的 Session 策略,盗取用户的身份信息

    CSRF攻击

  • 在打开 A 网站 的情况下,另开 Tab 页面打开恶意网站 B,此时在 B 页面的恶意意图下,浏览器发起一个对网站 A 的 HTTP 请求,因为之前 A 网站 已经打开了,浏览器存有 A 网站中的 Cookie 或其他用于身份认证的信息,这一次被 恶意意图的请求,将会自动带上这些信息,这将会导致身份劫持,造成并非本人意愿的操作结果

  • 而对应 CSRF 攻击的防御策略有:表单token、验证码、Referer 检测等

详细链接:CSRF 跨站请求伪造攻击 - JavaScript Guidebook


什么是 SQL 注入攻击?如何防止?

答:

  • SQL 注入攻击是攻击者在 HTTP 请求中注入恶意 SQL 语句,让服务端构造执行 SQL 语句时,恶意的SQL 被一起构造了,然后在数据库中执行,这样就可能对数据库造成全量数据拉取、删除、更新等敏感的操作
  • 预防 SQL 注入攻击,可以通过这几个方式:
    1. 使用参数化查询或预编译语句:使用参数化查询或预编译语句来构建和执行 SQL 查询。这样可以将用户输入的数据作为参数传递给查询,而不是将其直接拼接到 SQL 语句中,参数化查询可以防止恶意代码的注入
    2. 输入验证和过滤:对用户输入的数据进行验证和过滤,确保只接受合法的输入,可以使用白名单过滤、正则表达式验证或者编码转义等技术来防止恶意代码的注入
    3. 最小权限原则:在数据库中为应用程序使用最小权限的数据库账户,这样即使发生SOL注入攻击,攻击者也只能在该账户的权限范围内进行操作,减少损失

补充:

SQL 注入攻击指的是攻击者在 HTTP 请求中注入恶意 SQL 命令,服务器用请求参数构造数据库 SQL 命令时,恶意 SQL 被一起构造,并在数据库中执行,以便得到数据库中的感兴趣的数据或对数据库进行读取、修改、删除、插入等敏感的操作,从而导致数据被随意篡改

SQL注入攻击

详细链接:什么是 SQL 注入? | Cloudflare、实战1:如何用 PREPARE 防止 SQL 注入_SQL 入门教程-慕课网


网络编程


Socket 网络编程对应 TCP 三次握手的环节?

答:

  1. 服务端首先会通过 bind 函数给 socket 绑定 端口 和 IP 地址,然后调用 listen 函数,进行监听,然后调用 accpet 函数等待客户端建立连接
  2. 当客户端调用 connect 函数的时候,内核会随机生成初始化序号,放到 TCP 报文头部的序号字段中,同时把 SYN 标志设置为 1,这样就表示 SYN 报文。接着把这个 SYN 报文发送给服务端,之后客户端处于 SYN_SENT 状态
  3. 服务端收到 SYN 报文后,首先服务端也会随机生成初始化序号,放到 TCP 报文头部的序号字段中,然后对客户端的 初始化序号+1 作为 确认号,放到 TCP 报文头部的确认应答字段中,并将 SYN 和 ACK 标志设置为 1,这样就表示 SYN_ACK 报文,然后把该报文发给客户端,之后服务端处于 SYN_RCVD 状态
  4. 客户端收到服务端 SYN_ACK 报文后,客户端会回一个 ACK 确认报文,该报文的确认号是 服务端的初始化序号+1,并且 ACK 标志会设置为 1,之后客户端处于 ESTABLISHED 状态,这时候 connect 函数就返回了
  5. 服务端收到 ACK 确认报文后,服务端也进入处于 ESTABLISHED 状态,这时候 accpet 函数就返回已建立连接的 socket,后续与客户端进行通信,就是对这个 socket 进行读写操作

TCP三次握手


建立TCP连接,Socket 在 TCP 握手哪个阶段可以拿到连接?

答:

需要完成三次握手后,服务端才能通过 accpet 函数得到已经建立 TCP 连接的 socket

TCP三次握手


listen 的参数 backlog 意义是什么?

答:

backlog 参数的大小,是指定 TCP 全连接队列大小的参数之一。内核会从内核参数 somaxconn 大小和backlog 参数大小之间取一个最小值作为 TCP 全连接队列大小

补充:

Linux内核中会维护两个队列:

  • 半连接队列(SYN 队列):接收到一个 SYN 建立连接请求,处于 SYN_RCVD 状态
  • 全连接队列(Accpet 队列):已完成 TCP 三次握手过程,处于 ESTABLISHED 状态

TCP三次握手

1
int listen (int socketfd, int backlog)
  • 参数一 socketfd:为 socketfd 文件描述符
  • 参数二 backlog:这参数在历史版本有一定的变化在
    • 早期 Linux 内核 backlog 是 SYN 队列大小,也就是未完成的队列大小。在 Linux 内核 2.2 之后,backlog 变成 accept 队列,也就是已完成连接建立的队列长度,所以现在通常认为 backlog 是 accept 队列
    • 但是上限值是内核参数 somaxconn 的大小,也就说 accpet 队列长度= min(backlog, somaxconn)

详细链接:4.4 TCP 半连接队列和全连接队列 | 小林coding


当客户端多次发送连接,服务器没有accept,客户端会出现什么现象?

答:

我觉得会导致客户端无法和服务端建立 TCP 连接,因为如果服务端没有执行 accpet 的话,那么已经建立连接的 socket 会堆积到 TCP 全连接队列,如果 TCP 全连接队列占满了,服务端收到新的客户端 SYN 报文的时候,内核就会丢弃 SYN 报文

补充:

全连接队列


四次挥手对应 socket 中通信的部分,其中哪些是用户调用,哪些是内核完成的?

答:

第一次挥手和第三次挥手的 FIN 报文,都需要客户端或者服务端调用 close 函数触发的,第二次和四次挥手的 ACK 就是 内核 来完成

补充:

TCP四次挥手


如果客户端和服务端同时调用了 close() 会发生什么?

答:

双方会同时发送 FIN 报文,由于双方在等待 ACK 报文的过程中,都等来了 FIN 报文,这是一种新情况,所以连接会进入一种叫做 CLOSING 的新状态,它替代了 FIN_WAIT_2 状态。接着,双方内核回复 ACK 确认对方发送通道的关闭后,进入 TIME_WAIT 状态,等待 2MSL 的时间后,连接自动关闭

补充:

由于 TCP 是双全工的协议,所以是会出现两方同时关闭连接的现象,也就是同时发送了 FIN 报文

TCP四次挥手

详细链接:计算机网络:TCP同时打开和同时关闭 - 简书


怎么知道客户端关闭连接?

答:

  • (正常断开情况)如果客户端正常断开连接的情况下,会发起了第一次挥手 FIN 报文,服务端收到后,内核会插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 报文,如果 read 返回 0 了,就代表客户端关闭连接了
  • (异常断开情况)如果客户端突然宕机了,服务端无感知客户端已经不存在了,如果接下来服务端不会在发送任何数据的话超过一段时间后,TCP 就会开启保活机制,来探测客户端是否还存活,如果最终判断到客户端不存在了,服务端这边也会自动释放连接

详细链接:tcp 服务端如何判断客户端断开连接 - youxin - 博客园