1. TCP 和 UDP 有什么区别?

TCP 是一种可靠的、面向连接、基于字节流传输的传输协议,能够保证数据的顺序,但是其延迟比较大。一般适用于需要数据完整性和顺序的场景,比如文件传输、邮件、Web 网站。 UDP 是一种不可靠的、无连接、基于数据报传输的传输协议,不能保证数据的顺序,但是延迟比较小。一般适用于需要高性能要求和快速传输数据的应用,比如实时通讯、语音、视频、游戏等。

【注意】TCPUDP 都属于传输层

特性 TCP UDP
连接方式 面向连接 (三次握手) 无连接
可靠性和顺序保证 可靠,保证数据按顺序送达 不可靠,不能保证数据的顺序,而不能保证安全送达
流量控制/拥塞控制 提供流量控制和拥塞控制 没有流量控制和拥塞控制
头部大小 头部较大 (20 ~ 80 字节) 较小 (只有 8 字节)
性能 较低,延迟大 较高,延迟小
是否支持广播 不支持广播 支持广播
数据传输模式 通过字节流传输 通过数据报传输
适用场景 文件传输、Web、邮件等需要可靠性的传输 实时通讯、语音、视频、游戏等高性能要求应用
基于两者的协议 1. HTTP协议:超文本和多媒体内容的协议
2. HTTPS协议:基于HTTP协议上加了一层SSL / TSL 外壳,保证了数据传输的安全性
3. FTP协议: 文件传输协议,用来传文件到服务器的
4. SMTP协议:简单邮件协议,用于发送邮件的协议 (POP3 协议: 负责邮件接受的协议)
1. HTTP 3.0 协议: 基于 UDPQUIC 协议
2. DHCP 协议: 动态主机配置协议,动态配置 IP 地址
3. DNS :域名解析系统,将域名转变为机器刻度的 IP 地址

【ISO 和 TCP/IP 模型】

  • **ISO (7层) **: “物联网淑慧适用” : 物理层—数据链路层—网络层—传输层—会话层—表示层—应用层
  • TCP/IP (4层):链路层—网络层—传输层—应用层

ISO和TCP_IP协议结构图

【TCP 详解】

TCP包没有IP地址,网络层已经处理过了。但是有源端口和目标端口

  • 序列号 (Sequence Number):在建立连接的时候,主机生成随机数作为初始值, 经过 SYN 包 (第一次握手)传给接收端主机。每发送一次数据,累加数据字节数大小,用来确保传输是按照顺序接受的。
  • 确认应答号 (Acknowledgement Number) :用来表示下一次希望受到的数据序列号,发送端受到确认应答后可认为此序列号前数据已经被正常接受,防止出现丢包的情况。
  • 控制位 (TCP Flags): 下面的字段都是二进制来表示是否有效,01 分别表示无效和有效
    • ACK : 表示确认应答字段是否有效, TCP 规定除了第一次握手的 SYN 包以外,该位置必须为 1,也就是必须有效
    • **RST (Reset) **: 表示 TCP连接当中出现异常,是否需要强制断开连接,进行重置
    • SYN:表示是否用来建立连接 (第一次握手), 并设置其序列号的字段的初始值
    • FIN:表示是否结束 TCP 连接,如果为1, 后面不会再传输数据,断开连接。
  • 窗口大小 (Window / Advertise-Window):用于实现滑动窗口,进行流量控制,确保发送方不会超出接收方的处理能力,防止缓冲区溢出。滑动窗口机制是用来允许发送方在未收到接收方确认的情况下,连续发送多个数据包,提高传输效率。实现方式是,接收方在报文当中通知其剩余的缓冲区大小,发送方根据该信息调整发送窗口,动态控制数据流量。

TCP头部结构图

【TCP 面试题拓展】

有一个IP的服务端监听了一个端口,它的TCP最大连接数目是多少?

最大TCP连接数 = 客户端IP数 * 客户端的端口数

IPv4 当中,客户端的IP数目最多为 2^32, 客户端的端口数最多为 2^16,所以单机的TCP最大连接数为2^48。但是由于文件描述符和内存限制,一般没法儿达到理论上限。

【UDP 的首部结构】

UDP 对应用层传下来的保温,既不合并也不拆分,保留这些报文的边界, 只是加一个 UDP 头部。

  • 目标、源端口:表示 UDP 将数据发送到哪个进程
  • 包长度:表示 UDP 首部和数据的总长度
  • 校验和:用于确保 UDP 首部和数据在传输过程中未受损

UDP头部结构完整图

【TCP 和 UDP 能否使用同一个端口】

TCPUDP 可以使用同一个端口,因为这两个传输协议是完全独立的软件模块。数据包通过 IP包头中的协议号字段判断是 TCP 还是 UDP,并转发给相应的模块处理。然后, TCPUDP 模块根据端口号将报文转发给对应的应用程序。

TCP和UDP传输过程

2. 说说TCP的三次握手过程 ?

TCP 三次握手的过程如下:

  1. 客户端发送 SYN 给服务端,建立连接
  2. 服务端收到 SYN 消息之后,回复一个 SYN-ACK 确认消息,表示接收到了客服端的连接请求
  3. 客服端收到SYN-ACK 消息之后,再发一个 ACK 确认消息,表示收到服务器的SYN-ACK 消息,成功建立连接。

TCP三次握手过程

【TCP 三次握手的实现细节】

最开始的时候,客户端和服务端都处于 CLOSE 状态,表示双方没有建立连接。服务端主动监听某个端口,处于LISTEN 状态。

【第一次握手】

  1. 客户端随机初始化 client_isn 值,将其设置为TCP 头部的序列号字段。
  2. 将标志位的 SYN 设置为 1,表示该报文为 SYN 报文。
  3. 客服端将该报文发送给服务端,之后客户端处于 SYN-SENT 状态。表示向服务端发起 TCP 连接,该报文不包含应用层的任何数据,只用于建立连接。

TCP三次握手过程-第一次握手

【第二次握手】

  1. 服务端收到客户端 SYN 报文知乎,随机初始化序号server_isn , 并把它填入 TCP 头部的序列号字段。
  2. 将确认应答好修改为 SYN 报文中的序列号 + 1,也就是client_isn + 1。并把SYNACK 的标记位都改为1,该报文为 SYN-ACK 报文
  3. 发送 SYN-ACK 报文给客户端,不包含任何应用层数据,只用于确认收到客户端的 SYN 报文,服务端进入 SYN-RCVD 状态

TCP三次握手过程-第二次握手

【第三次握手】

  1. 客户端收到服务端的 SYN-ACK 报文,准备回应最后的应答报文
  2. 把报文的 TCP 头部的确认应答号修改为 SYN-ACK 报文的序列号 + 1,也就是server_isn + 1ACK 标志修改为 1, SYN 不做任何修改,依然为 0,该报文表示 ACK报文。
  3. 把报文发送给服务端,可以携带应用层的数据,之后客户端处于ESTABLISHED 状态,表示成功建立连接。

TCP三次握手过程-第三次握手

**【注意】**第三次握手是可以携带数据的,但是前两次握手都不能携带数据。并且就算第三次握手丢失,服务端依然可以根据数据包来得到第三次握手的信息 (用序列号进行判断,找client_isn + 1 的数据包)。如果第三次握手 ACK 确认包丢失了,但是收到了客服端发的携带数据的包,并且包含 ACK 标记, 服务端默认表示第三次握手有效,成功建立连接。然后处理该数据包并继续正常传输数据。

【TCP 三次握手中每次握手的意义】

客户端和服务端需要通过三次握手来确认双方的发送和接受都是正常的

  1. 第一次握手:服务端确认客户端发送正常,自己接受正常。客户端无法确认。
  2. 第二次握手:客户端确认自己发送和接受正常,服务端接受正常。服务端确认自己接受正常,客服端发送正常。
  3. 第三次握手:客户端和服务端都确认自己和对方,彼此发送和接受都是正常的

【为什么是三次握手,不是两次或者四次呢?】

避免浪费资源:如果只有两次握手,无法阻止历史连接。服务端在向客户端发送数据之前,没有阻止掉历史连接 (第一次 SYN 请求到达就会建立连接),从而导致服务端建立了一个历史连接。如果客户端发送了 多个SYN 报文,就会不断重复建立连接,浪费资源。如果采用四次握手,就需要多一次不必要的操作,也会浪费资源。

TCP两次握手连接案例

【为什么每次建立TCP连接的时候,初始化的序列号要求不一致?】

  1. 防止历史报文被下一个相同的四元组连接接受
  2. 防止黑客伪造相同序列号的 TCP 报文被对方接受

【什么是半连接队列和全连接队列?】

TCP 三次握手的过程当中, Linux内核会维护两个队列来管理连接。

  • 半连接队列 (SYN Queue): 服务端收到客户端的 SYN 请求后,双方未完全建立连接,会将半连接状态的连接放入半连接队列
  • 全连接队列 (Accept Queue):服务端收到客户端对 ACK 响应的时候,意味着三次握手完成,服务端将该连接从半连接队列移动到全连接队列。

TCP三次握手中的半连接队列和全连接队列

3. TCP 用来解决什么问题的?

TCP 协议主要是通过可靠传输、流量控制、拥塞控制和连接管理,解决数据在不可靠的IP网络上传输的问题。

  • 可靠性:TCP 确保数据包在网络传输的过程当中不丢失、不重复,并且按顺序到达。通过确认-重传机制和序列号,保证数据在IP网络上的可靠传输。
  • 流量控制:TCP 通过滑动窗口机制调节发送方(客户端)的发送速率,防止接收方因为处理能力或者缓存有限,而导致数据流被淹没或者丢失。
  • 拥塞控制:TCP 通过拥塞避免算法 (比如慢启动、拥塞避免、快速重传和快速恢复) 来防止网络过载,确保网络资源的公平使用和稳定性。
  • 连接管理: TCP 是面向连接的协议,采用三次握手建立连接,四次挥手断开连接,来管理连接会话,确保通信的可靠性和状态的同步。

4. 说说 TCP 的四次挥手?

TCP 的四次挥手是用来安全关闭已经建立的连接的过程,它可以确保双方都能完成数据传输并且安全释放连接资源。四次挥手的过程如下所示:

  1. 第一次挥手:客户端发 FIN (seq_num = x) 数据包到客户端,表示其申请关闭服务端的数据传送,随后进入FIN_WAIT_1 状态,等待服务端进行确认。
  2. 第二次挥手:服务端收到客户端的 FIN (seq_num = x) 数据包之后,发送 ACK (ack_num = x + 1, seq_num = y) 给客户端,表示确认收到 FIN 数据包,随后进入 CLOSE_WAIT 状态。客户端接收到 ACK 包之后,进入FIN_WAIT_2 状态。同时,服务端会将没有传送完的数据传给客户端。
  3. 第三次挥手:服务端发送 FIN (seq_num = w) 的数据包给客服端,请求关闭连接,进入 LAST-ACK 状态。
  4. 第四次挥手:客户端收到 FIN 数据包之后,发送 ACK (ack_num = w + 1)数据包,随后进入 TIME-WAIT 状态。服务端收到此数据包之后,进入 CLOSE 状态。如果客户端等待 2MSL 没有收到回复的话,证明服务端已经正常关闭,此时客户端也进入 CLOSE 状态。

【注意】

  1. 四次挥手过程中,服务端 (被动关闭的一方) 在 CLOSE_WAIT 的状态下,仍然可以发送数据,直到它主动发送FIN 请求关闭连接。
  2. 客户端(主动关闭连接的一方) 发出 FIN 后,无法再传输数据,只能接受数据
  3. 只有客户端 (主动关闭的一方) 会进入TIME_WAIT 状态,用于等待潜在的重传 FIN

TCP四次挥手

【为什么需要四次挥手】

为了确保数据的完整性,服务器需要把没有发送完的数据全部传输完之后,再关闭连接。所以,服务端的 ACK 确认包 和 FIN 请求关闭包,一般都会分开发送,所以需要四次挥手。TCP 为全双工通信,可以双向传输数据。任意一方数据传输结束都可以发送连接释放通知,对方确认后进入半关闭状态。另一方无数据再发送的时候,也发连接释放通知,双方确认则完全关闭TCP连接 (客户端和服务端都需要一来一回,请求释放和确认一次)

【什么情况下会出现三次挥手】

如果服务端没有数据需要发送了,并且开启了 TCP 延迟确认机制 (默认开启),第二次和第三次挥手就会合并传输 (ACKFIN),就会出现三次挥手。

5. TCP 的粘包和拆包能说说吗?

【定义】

  • 拆包 / 半包:客服端 (发送方) 要发送的包太大了,必须拆分成多个包进行发送。导致一条完整的消息要被拆分为多个部分,服务端 (接收方) 无法一次性接受完整的数据。
  • 粘包:客户端 (发送方)要发送的包太小了,会将多个包放在数据缓存区,合并成一个包发送出去。服务端(接收方)在读取的时候,可能将多个消息拼接在一起。导致多条消息数据粘在一起,服务端 (接受方) 无法区分这些消息的边界。

【原因】

  • 拆包 / 半包:由于网络传输中的 MTU 最大传输单元限制或者发送缓冲区的大小的限制,一个大包必须被拆分为多个小包。
  • 粘包:由于 TCP 是基于字节流传输的协议,不关心数据的边界。数据在发送方可能被一次性发送,接收方读取的时候可能会将多个消息拼接在一起。

【注意】 只有 TCP 协议才会出现粘包和拆包的现象,UDP 协议不会出现这种情况。因为 TCP 协议的包没有报文长度,而 UDP 的包有报文长度。 所以TCP 是流式的,数据之间没有界限,而 UDP 是有界限的。

TCP拆包和粘包

【解决方案】

  1. 固定数据包的长度:客户端每次发送数据包的时候,统一数据包的长度。比如采用 1024 字节,如果数据不足,就采用空格进行填充。

  2. 添加分隔符:客户端在每个数据包的末尾用固定的分隔符 (比如 \r\n;)。服务端收到数据包之后,根据分隔符进行合并或拆分头部与前包剩余的部分,获取完整数据包。

  3. 固定消息头部和消息体:采用固定长度的头部记录整个消息的长度,读取到足够长度数据,才视为完整消息。

    TCP粘包拆包解决方案-固定消息头

  4. 禁用Nagle协议:为了减少网络中的小包数量,TCP 采用了 Nagle 算法,将小数据块缓冲起来,直到缓冲区满了或者收到接受方的确认之后,再发送数据包。该算法可能会导致粘包现象,所以在需要实时传输小数据包的场景,可以设置 TCP_NODELAY 禁用 Nagle 算法,减少粘包的可能性。

6. 说说 TCP 阻塞控制步骤 ?

阻塞控制机制:就像高速公路上的交通管理,目的是防止数据流量过大导致网络“拥堵”。当网络开始“拥塞”时,TCP会自动减慢数据发送速度,以确保网络保持畅通。

滑动窗口机制:这是一种流量控制方法,确保发送方不会发送超过接收方处理能力的数据量。可以类比为水管中的水流,滑动窗口就像一个阀门,调节水流量,防止水管溢出。

【注意】 假设拥塞窗口 为 cwnd 和 流量控制的滑动窗口 为rwnd,当前窗口的右边界受这两个值共同影响,应该取它们之间的最小值。

窗口大小 = min(cwnd, rwnd)

【阻塞控制步骤】 阻塞控制可以分为两种情况来看,分别是超时重传 (基于超时的拥塞控制) 和快速重传 (基于重复 ACK 的拥塞控制)

  • 超时重传:当客户端检测到数据包传输超时 (未收到 ACK 确认),会认为网络出现严重阻塞。此时,TCP会采取最保守的策略:将拥塞窗口cwnd 重置为 1,并重新进入慢启动阶段, 同时将慢启动阈值ssthresh 设置未当前拥塞窗口的一半
  • 快速重传:当客户端连续收到3个重复的 ACK (比如服务端检测到报文段失序的时候,会触发该机制),表明网络中可能只发生了单个数据包丢失而非全局阻塞。此时,TCP会出发快速重传 (立即重传丢失的数据包) 和 快速恢复 (调整拥塞窗口 cwnd 为 慢启动阈值 + 3 ssthred + 3,避免完全退回到慢启动)。

TCP阻塞控制

TCP 协议的拥塞控制主要通过五个算法来实现:慢启动、拥塞避免、超时重传、快速重传和快速恢复。

  • 慢启动:发送方开始设置一个较小的拥塞窗口大小,在每收到一个新的报文段的 ACK 确认之后,每当成功发送跟拥塞窗口大小等量的数据后,拥塞窗口大小就会翻倍。拥塞窗口按照指数方式增长,直到拥塞窗口 cwnd 达到 慢启动门限 ssthresh
  • 拥塞避免:当拥塞窗口大小 cwnd 达到 慢启动门限 ssthresh 之后,就进入拥塞避免阶段。每当成功发送跟拥塞窗口大小等量的数据之后,拥塞窗口大小就会增加一个报文段的大小,以线性的方式增长。
  • 拥塞发生:随着发送速率慢慢加快,可能会出现网络阻塞现象,发生数据包丢失。此时,就需要重传数据。重传的机制有两种,超时重传和快速重传。
  • 超时重传:当发生超时重传的时候,慢启动门限ssthresh会设置为拥塞窗口的一半,并且将拥塞窗口恢复为初始值。随后重新开始慢启动,发送速率就瞬间下降了。
  • 快速重传和快速恢复:当客户端连续收到3个重复的 ACK (比如服务端检测到报文段失序的时候,会触发该机制),就认为发送了丢包。此时,拥塞窗口会 cwnd 减少到原来的一半,然后慢启动门限 ssthresh 设置为减少后的拥塞窗口的大小 cwnd,然后进入快速恢复阶段。此时,会把拥塞控制窗口+3 (cwnd + 3), 3 的意思是确认有 3 个数据包收到了。然后重传丢失的报文,如果收到重传丢失报文的ACK 之后,将拥塞窗口设置为慢启动门限,直接进入拥塞避免,继续增大发送速率。

7. 常见的 HTTP 状态码有哪些?

常见的 HTTP 状态分为五大类,有三位数字,一般用第一位数字来区分类别。

  1. 1xx 信息状态码 : 协议处理中的中间状态,还有后续操作
    • 100 Continue:服务器接收到请求的初步部分,客户端需要继续请求
    • 101 Switching Protocols:服务器同意切换协议,比如:从 HTTP 协议切换到 WebSocket 协议
  2. 2xx 成功状态码:服务器成功处理客户端请求
    • 200 OK: 请求成功,服务器返回所请求的资源或数据
    • 201 Created: 请求成功并创建新的资源,一般用于 POST 请求
    • 202 Accepted:服务端收到请求,但是还未处理
    • 204 Not Content:请求成功但是服务器不返回任何内容,常用于删除
    • 206 Partial Content:请求成功但服务器返回部分资源,一般用于HTTP分块下载或者断点续传
  3. 3xx 重定向状态码:客户端用新的 URL 重新发送请求获取资源
    • 301 Moved Permanently:永久重定向,资源已经移动到新的 URL,通知客户端用新的 URL 访问
    • 302 Found:资源临时移动到新的 URL, 客户端应该继续使用原来的 URL。允许浏览器将 POST 请求转换为 GET
    • 303 See Other:和 302 有相同的功能,但是 303 明确要求客户端采用 GET 方法获取资源
    • 304 No Modified:缓存重定向,资源没有被修改。客户端可以继续使用缓存资源,减少带宽消耗
    • 307 Temporary Redirect:临时重定向,和 302 的含义几乎差不多。但是 307 需要保证重定向时请求方法和主体不变。
  4. 4xx 客户端请求错误状态码:客户端发送的报文有误,服务器无法处理
    • 400 Bad Request:客户端请求报文无效或者语法错误
    • 401 Unauthorized: 请求需要身份验证,客户端未提供有效的凭证
    • 403 Forbidden:服务器理解该请求,但是拒绝执行,一般是客户端没有权限访问
    • 404 Not Found: 请求的资源在服务器上找不到,比如 URL 的一部分写错了
    • 409 Conflict: 请求的资源和服务器的当前状态存在冲突
  5. 5xx 服务端错误状态码:客户端请求的报文正确,但是服务器处理的时候内部发送错误。
    • 500 Internal Server Error:服务器内部错误,无法完成请求,而且不知道是什么错误
    • 501 Not Implemented:还不支持客户端请求,类似于“即将开业,敬请期待”的意思
    • 502 Bad Gateway:服务器作为网关或者代理,从上游服务器收到无效响应。比如调用其他网站的API 发生错误的时候
    • 503 Service Unavailable:服务器暂时无法处理请求,一般是因为处理维护中,或者服务过载

8. HTTP 请求包含哪些内容,请求头和请求体有哪些类型?

【请求报文】 请求报文主要包括四个部分,请求行,请求头,空行(分割请求头和请求体),请求体。

  • 请求行:包含请求方法 (GET / POST) 、请求路径 /doc/test.html) 和 HTTP 版本 (HTTP/1.1)
  • 请求头:包含各种键值对,客户端环境(User-Agent)、请求内容 和认证信息 (Token) 等等
  • 空行:用于分割请求头和请求体
  • 请求体:只在 POSTPUT 方法中存在,包含需要发送到服务器的信息

HTTP请求报文

【响应报文】 响应报文主要包含四个部分,状态行,响应头,空行,响应体

  • 状态行:包含 HTTP 的版本 (HTTP/1.1)、状态码 (200) 和状态描述 (OK)
  • 响应头:包含服务器返回的各种键值对,用于描述响应的元信息,常见的响应头如下
    • Content-Type:响应额呢绒的类型, 一般为 text/html / application/json
    • Content-Length: 响应内容的字节长度
  • 空行:用于风格响应头和响应体
  • 响应体:包含服务器返回的实际内容,比如 HTML文档、图片、JSON数据等

HTTP响应报文

【HTTP 常见请求方法】

  • GET:获取指定的资源
  • POST: 传输实体数据,POST 一般用来传数据,GET 一般用来获取数据
  • PUT: 上传文件,由于自身没有验证机制,任何人都可以上传文件
  • DELETE: 删除文件,和 PUT 功能正好相反,同样没有验证机制

9. HTTP 中 GET 和 POST 的区别是什么?

特性 GET POST
主要用途 获取服务端的资源 向服务器提交数据,一般用于创建或者修改
参数传递 参数都在 URL 参数都在请求体当中,URL 也可以放参数
安全性 参数可见,数据容易暴露在浏览器的历史记录、日志和缓存里面,不适合传递敏感信息,不安全 数据放在请求体中,相对安全,但是需要HTTPS才能保证数据加密传输 (不然会被抓包)
幂等性 只读操作,多次请求不会改变服务器状态 修改操作,多次请求可能会导致重复创建资源,或者执行多次相同操作
长度限制 请求参数在 URL 中,浏览器对 URL 有长度限制 请求参数放在请求体中,理论上来说没有任何限制。但一般服务器对请求体长度有配置限制,比如 Nginx 默认限制为 1MB
缓存机制 浏览器和CDN都会缓存 GET 请求的数据,用于减少服务器的负载,比如图片、静态页面等不会频繁改动的静态资源 一般不会缓存 POST 请求,因为它通常对服务器数据会产生影响

【注意】 幂等意味着相同的请求重复多次,服务器的状态只会改变一次,不会累计多次副作用,而非幂等请求每次调用可能引起状态的多次改变

【GET 请求一定是幂等的吗?】

不一定,因为如果有开发者不遵循规范去处理请求,采用 GET 方式来新增数据,这时候 GET 请求就不是幂等的了。曾经有个笑话,有人写了个博客,删除博客用的是 GET 请求,他觉得没人访问就连鉴权都没做。然后 Google 服务器爬虫爬了一遍,他所有博文就没了…

10. HTTP 1.0、HTTP 1.1、HTTP 2.0、HTTP 3.0 区别?

【区别】

特性 HTTP 1.0 HTTP 1.1 HTTP 2.0 HTTP 3.0
连接方式 短连接 持久连接 持久连接 QUIC 连接 (基于UDP)
传输方式 文本 文本 二进制 二进制
多路复用 不支持 不支持 支持 支持
服务器推送 不支持 不支持 支持(主动推送资源) 支持(增强资源推送效率)
头部压缩 不支持 不支持 支持 (HPACK) 支持 (QPACK)
安全性 明文传输(需 HTTPS 加密) 明文传输(需 HTTPS 加密) 强制建议 HTTPS 默认集成 TLS 1.3, 支持HTTPS
是否解决队头阻塞问题 存在(单请求阻塞) 部分缓解(管道化请求,但响应仍需顺序接收) 基本解决(TCP 连接内多路复用) 彻底解决(QUIC 协议是基于UDP协议,没有阻塞队列)
典型改进 定义了基础 HTTP 协议 长连接、断点续传、Host 头域 二进制协议、头部压缩、多路复用 基于 UDP 的 QUIC 协议、零 RTT 连接、抗网络切换
适用场景 静态网页、简单文件下载 中小型网站、内部管理系统 (非高并发网站) 高并发网站(淘宝/微博)、动态加载的单页应用、视频流媒体 实时通信(视频会议/在线游戏)、移动端应用(5G/弱网环境)、物联网设备通信

【HTTP/1.0】

  • 无状态、短连接:每次请求都需要建立新的TCP连接,处理完之后立即关闭,导致开销比较大
  • 队头阻塞:每个请求必须按照顺序依次处理,前面的请求还没完成,后面的请求只能等待,并发效率不高

【HTTP/1.1】

  • 持久连接:引入了连接复用(Keep-Alive),只要任意一端没有明确提出断开连接,就保持TCP连接状态。减少TCP握手开销
  • 管道传输:在一个TCP链接里面,客户端发送多个请求,只要一个请求发出了,不用等待响应,直接发送第二个请求。该策略可以减少整体的响应时间。
  • 队头阻塞:当顺序发送的请求序列中的一个请求,可能因为某种原因被阻塞的时候,后面排队的所有请求也一同被阻塞了,会导致客户端一致请求不到数据。
  • HOST字段:可以在同一个IP地址上运行多个虚拟主机
  • 断点续传:支持文件传输中断后,从断点出继续传输。

【HTTP/1.0 和 HTTP/1.1 缓存机制区别】

  • HTTP/1.0 缓存机制:基于时间的缓存机制,用请求头中的 If-Modified-Since 和响应头中的 Last-Modified 字段实现

    • 响应头中的 Last-Modified :表示响应资源的最后修改时间

    • 请求头中的 If-Modified-Since :请求的时候修改为响应头的 Last-Modified 时间。当服务器受到该请求之后,会对比请求资源最后修改的时间Last-Modified。 如果从 If-Modified-Since 没有修改,直接响应 304 Not Modified 走缓存。如果已经被修改过,返回最新资源, 响应 200 OK

  • HTTP/1.1 缓存机制:基于唯一标识的缓存机制,用请求头中的 If-None-Match 字段和响应头中的 ETag 字段实现

    • 响应头中的 ETag:表示响应资源的唯一标识,可以看成是一个id
    • 请求头中的 If-None-Match :当资源过期的时候,浏览器发现响应头里面有 ETag,再次想服务器发起请求的时候,将If-None-Match 设为 Etag 的值。服务器受到请求后进行对比,资源没变化,返回304。资源有变化,返回信的资源,响应200

HTTP-缓存机制

【HTTP/2.0】

  • 多路复用:支持一个TCP连接中,传输多个请求和响应,解决了 HTTP/1.x 中的串行问题

  • 二进制帧:使用二进制桢格式,头信息帧和数据帧分离,提高传输效率。其中桢数据(Data Frame),会被头部压缩

    HTTP-二进制帧

  • 头部压缩 (HPACK): 通过静态表和动态表对HTTP头部进行压缩,减少带宽占用。客户端和服务端维护同一张头信息表,所有字段都会存储这个表,生成一个索引号,以后发送后借助索引号提升速度。

    HTTP-头部压缩

  • 服务器推送:服务器可以主动向客户端推送资源,减少请求延迟。HTTP/1.1 需要从服务器获取HTML文件,如果还需要获取 CSS渲染页面,需要再次发起获取 CSS文件的请求,就需要两次消息往返。HTTP/2.0 服务器可以主动向客户端发送HTML和CSS文件信息,双方建立 Stream

    【注意】 客户端的 Stream 必须是奇数号、服务器建立的 Stream 必须是偶数号

    HTTP-服务器推送

【HTTP/3.0】

  • RTT: Round Trip Time 往返时间
  • RTO: Retransmission Timeout 超时重传时间
  • QUIC 协议:基于UDP协议,QUIC 通过自身实现可靠传输,减少了 RTT。参考材料:QUIC如何实现可靠传输

  • 多路复用:在一个 QUIC 协议上,可以同时传输多个请求和响应,并支持流优先级。QUIC 当中每个 stream 之间是相互独立的,假如单个 stream 丢失了,不会影响其他的stream,彻底解决了队头阻塞问题。但是,因为UDP是无序交付的,数据不一定按照发送时的顺序到达。

    HTTP3-QUIC-多路复用

  • 更快的连接建立:模拟TCP的三次握手操作,但是握手过程只需要一个往返时间RTT ,用于确认双方的连接IDQUIC 内部包含了 TLS/1.3 ,其帧携带了 TLS 记录, 所以不需要 TLS 握手。

    HTTP-QUIC-更快的连接建立

11. TCP/IP 四层模型是什么?

TCP/IP 四层模型是一个分层网络通信模型,这四层从底向上分别是:网络接口层 (物理层+数据链路层)、网络层、传输层、应用层 (会话层+表示层+应用层)

  1. 网络接口层:负责数据桢的封装和物理传输 (比如以太网、WIFI、PPP拨号协议等)
  2. 网络层:负责数据包的路由和寻址 (比如 IP、ARP、NAT等协议)
  3. 传输层:负责端到端的通信 (比如TCP、UDP)
  4. 应用层:负责为用户提供应用服务 (比如 HTTP、域名服务器 DNS、邮件 SMTP和POP3、FTP、SSH、动态IP地址分配 DHCP)

TCPIP四层模型架构图

【应用层】 提供两个终端设备上的应用程序之间信息交换的服务 (比如两个QQ发消息),定义了信息交换的格式,消息会交给下一个传输层来传输

【传输层】 负责将两台设备进程之间的通信提供通用的数据传输服务,应用进程利用该服务传送应用层的报文。

【网络层】 分组交换网上的不同主机提供通信服务,选择合适的路由,让源主机传输层传下来的分组,可以通过网络层中的路由器找到目的主机。路由器寻址工作中,要找到目标地址的子网,找到后进而把数据包转发给对应的网络内。

网络层常见的协议如下:

  • IP :用于对数据包进行路由和寻址
  • ARP:用于将IP地址和MAC地址进行相互转换
  • NAT:用于将内部IP和外部IP进行相互转换
  • ICMP:用于传输网络状态和错误消息的状态,一般用来网络诊断和故障排除

【网络接口层】 将网络层的IP数据报组装成帧,在相邻节点之间的链路传送。每一帧含数据和必要的控制信息 (比如同步、地址、差错控制等信息)。实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异

TCPIP协议的传输过程图

12. Cookie、Session、Token 之间有什么区别?

特性 Cookie Session Token
用途 用于跟踪和保护用户状态信息的小型数据文件 用于保存用户状态的机制,每个会话都有一个唯一的Session ID 一串加密字符串,用于身份校验
存储位置 客户端 (浏览器) 服务器 客户端 (浏览器、移动设备)
是否有状态 没有 有状态 没有
适用场景 轻量级状态存储 (用户偏好、个性化设置) 用户身份认证、临时会话数据存储 分布式认证、移动端和单页应用 (SPA)
适用协议 HTTP/HTTPS HTTP/HTTPS HTTP、HTTPS、WebSocket
安全性 较低:容易被篡改或者伪造 较高:数据存储在服务端 较高:Token通常加密且支持签名和过期机制

【Cookies 详解】

  1. 服务器通过 HTTP 响应头 (Set-Cookie) 返回Cookie给客户端
  2. 客户端保存 Cookie,后续所有同源的请求,都会携带该 Cookie
  3. 服务器根据 Cookie 的值 (比如 SessionID) 识别用户状态

【注意】 Cookie是HTTP协议簇的一部分,HTTP协议没有状态,每个请求都是独立的。所以Cookie是无状态协议下在客户端存储状态信息的补充机制

Cookies工作流

【Session 详解】

  1. 用户登录的时候提交包含用户名和密码的表单的HTTP请求报文,服务器验证该用户和密码
  2. 如果正确,则把用户信息存储到 Redis / ConcurrentHashMap 里面, keySession IDvalue 包含用户的信息
  3. 服务器返回的响应报文中,头部的 Set-Cookie 字段包含该Session ID,客户端收到响应报文后存储Cookie值
  4. 客户端后续请求同一服务器会包含Cookie值,服务器会提取当中的 Session ID,从Redis里面提取用户信息,继续业务操作。

Session工作流

【Cookie 和 Session 的关系】

Session 的主要作用就是通过服务端记录用户的状态, Cookie就是在客户端保存对应的Session ID。典型的场景就是购物车,服务端给指定用户创建 Session 之后,就可以标识这个用户并且跟踪这个用户。

【分布式 Session共享问题】

假如在一个秒杀场景下, 每个用户只能进入一次秒杀页面。但是,用户在请求的过程当中,Nginx可能会将其负载均衡到不同的 Tomcat。比如第一次请求到 Tomcat A 记录 Session, 然后购买了商品。但是,第二次请求到 Tomcat B 就会出问题,因为 Tomcat B 认为用户第一次来而允许购买请求,造成重复购买。因为每台 Tomcat 当中,只能看到自己存储的Session

【Token 详解】

  1. 客户端用用户名和密码登录服务器
  2. 服务端验证身份之后生成Token并返回给客户端
  3. 客户端将Token存到本地浏览器 (一般存到Cookie里面)
  4. 客户端发起请求的时候携带Token,服务端收到请求后,先验证Token再返回数据

Token-Cookie对比

Token一般都采用 JWT 算法进行颁发令牌,其主要构成如下:

  • Header:描述JWT元数据,定义生成签名的算法和 Token 类型
  • Payload:用来存放实际需要传递的数据集
  • Signature:服务器利用Payload、Header 和密钥 (Secret),采用Header指定的签名算法 (默认为HS256) 生成

【注意】 JWT一般存在 LocalStorage 本地存储当中,放在Cookie 会有跨站请求伪装CSRF 风险,一般请求服务端携带JWT的长火箭做法是使用 HTTP Header 中的 Authorization 字段

JWT算法结构

13. 从网络角度来看,用户从输入网址到网页显示,期间发生了什么?

  1. 用户在浏览器输入指定网页的URL,浏览器解析URL路径
  2. 浏览器通过DNS协议,获取域名对应的IP地址 (先找本地缓存,找不到就找配置的DNS服务器)
  3. 浏览器根据IP地址和端口号,向目标服务器发起一个TCP连接请求 (三次握手)
  4. 浏览器在TCP连接上,向服务器发送一个HTTP请求报文,封装成IP数据包,请求获取网页内容
  5. 操作系统在IP数据包的基础上加上MAC头部,加上发送方MAC地址和接受方目标MAC地址 (ARP协议)
  6. 数据包还是存储在内存中的二进制数据,网卡将二进制数据转为电信号,通过网线进行传输
  7. 交换机收到数据包之后,会根据数据包中的MAC头找到另外一个设备连接在交换机的哪个端口,然后传输。(如果找不到,就对所有的端口进行广播)
  8. 路由器收到数据包之后根据IP地址,在不同的网络节点之间转发,最后到达服务器。(如果超过TTL,还没找到服务器,则说明服务器不可达)
  9. 服务器收到HTTP请求报文之后进行处理,重复上面的过程,返回HTTP响应报文给浏览器
  10. 浏览器收到HTTP响应报文之后,解析HTML代码渲染网页结构和央视。同时根据HTML中的资源URL再次发起请求,获取资源内容 (比如一些图片资源),直到网页完全加载
  11. 浏览器再不需要和服务器进行通信的时候,主动关闭TCP连接或等待服务器关闭请求,进行四次挥手。

用户输入一个网址到网页显示的完整过程

【URL 结构】

  • Schema 协议类型:一般为HTTP/HTTPS协议,也可能是文件传输协议 FTP, 邮件协议 SMTP
  • 域名 + 端口:域名是网址的通用名或者IP地址的可读版本,端口就在域名后面,用冒号隔开
  • 资源路径:指明要访问哪一个网页/资源
  • 参数:参数用键值对的形式 key = value,用 & 进行隔开
  • 锚点:锚点以#开头,是页面上的锚,用于定位,不发送给服务端

URL的构成

【域名解析】

  1. 查询本地的Host文件/列表:浏览器回去查询本地是否有对应域名的记录, 如果有,直接提取对应的IP地址

  2. 查询本地DNS缓存: 查询浏览器缓存/操作系统缓存/路由器缓存,如果存在记录,直接提取对应的IP地址

  3. 查询DNS服务器: 如果缓存没有命中,浏览器会向配置的DNS服务器发送查询请求 (通常由运营商 ISP 提供),DNS服务器会通过递归查询的方式解析域名

    • 根DNS服务器:返回顶级域名的服务器地址 (.com)
    • 顶级域名(TLD)服务器:返回权威DNS服务器的地址
    • 权威DNS服务器: 返回具体域名的具体IP地址

    DNS服务器查询过程

14. HTTP 和 HTTPS 的区别?

先说区别,上表!!!

特性 HTTP HTTPS
安全性 明文传输,不安全 采用TLS / SSL 安全协议,让报文加密传输
连接过程 基于 TCP 协议,三次握手之后,即可发送报文信息 基于 TCP + SSL / TLS 协议,在 TCP 的三次握手之后,还会进行 SSL / TLS 的握手过程,才能进行加密报文传输
默认端口 80 443
数字证书 不需要数字证书 需要向 CA (Certificate Authority) 证书权威机构申请数字证书,确保服务器的身份是可信的

HTTP和HTTPS区别

【为什么需要 HTTPS协议】

传统的 HTTP 协议存在下面的三种安全风险隐患:

  • 窃听风险:通信链路上可以获取通信内容,用户信息容易被盗窃 (抓包)
  • 篡改风险:比如在服务器返回的报文里面,强行植入垃圾广告,用户容易误触进入垃圾网站
  • 冒充风险:伪装成天猫、京东等官方网站,用户容易被骗钱。

HTTPS 就可以很好的解决上面的三种风险,具体方案如下:

  • 信息加密 (解决窃听):网络报文传输的过程中,报文时加密的,抓包拿到报文也没用
  • 校验机制 (解决篡改):无法篡改通信内容,篡改之后就不能正常显示。HTTPS 会通过消息认证码 (MAC) 或者数字签名确保数据完整。
    • MAC机制:发送方用密钥生成数据的哈希值 (HMAC), 接收方重新计算并进行对比额如果哈希值不匹配,则说明数据被篡改。
    • 数字签名CA 对证书内容哈希值加密生成签名,客户端验证签名一致性,防止证书内容被篡改
  • 身份证书:通过 CA 颁发的证书,验证当前网站是否为真实的网站。

【HTTPS详解】

下面围绕 HTTPS 解决三大风险(窃听、篡改、冒充)的方案进行展开

【窃听风险 (混合加密)】

为了解决窃听风险,HTTPS对报文采用了混合加密的方式 。HTTPS 采用的是对称加密 + 非对称加密的方式来实现混合加密的。具体方式如下:

  • 在通信建立前,采用非对称加密的方式交换会话密钥,后续不再使用非对称加密
  • 在通信过程中,全部使用对称加密的会话密钥加密明文数据

为什么会采用混合加密呢?主要是单个加密方式都有其对应的缺点,具体加密特点如下:

  • 对称加密:只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换
  • 非对称加密:需要使用两个密钥,公钥和私钥,公钥可以任意分发而私钥需要保密,解决了密钥交换问题,但是速度慢

为了均衡速度和安全的性能,HTTPS 采用混合加密方式进行加密 HTTPS-混合加密

【篡改风险 (摘要算法 + 数字签名)】

为了解决篡改风险,HTTPS对报文采用了摘要算法 + 数字签名的方式 。为了保证传输的内容不被篡改,需要对发送方的报文内容进行哈希计算,计算出其哈希值,然后放在报文内容当中一起传输给客户端。如果对方收到报文内容之后,同样会先计算报文的哈希值。如果计算出来的哈希值和报文本身携带的哈希值不一样,就说明报文被篡改了,会丢弃这条数据。

HTTPS 协议采用摘要算法 (哈希函数) 来计算报文内容的哈希值,哈希值是唯一的,并且没法儿通过哈希值反推内容,可以防止报文在传输的过程当中被篡改。但是,如果有中间人将内容和哈希值同时进行篡改,接收方是没法儿判断报文是否是源于发送方发出的还是中间人发出的。为此,HTTPS 协议采用了非对称加密算法,利用私钥哈希值生成数字签名来解决这个问题。 发送方会把内容和数字签名(私钥加密之后的哈希值)一起发送出去。接收方收到之后,采用公钥对数字签名进行解密。并且同时对内容进行哈希运算,如果内容计算的哈希值数字签名解密的哈希值相同,则说明消息没有被篡改。否则,说明消息被篡改了,直接丢弃。 【公钥和私钥关系】 公钥和私钥是可以双向加解密的,也就是说可以用公钥加密,私钥解密,或者用私钥加密,公钥解密。

  • 公钥加密,私钥解密:一般用于防止传输的内容被窃取,其他人是截取到报文,也是没法儿解密的。只有持有私钥的人,才能够解密。
  • 私钥加密,公钥解密:一般用于防止传输的内容被冒充,因为私钥是不可泄露的,如果公钥能够解密出私钥的内容,证明这条消息是私钥身份的人发送的。

HTTPS-摘要算法-数字签名

【冒充风险 (数字证书)】

虽然前面通过哈希算法能够保证消息不被篡改,且通过数字签名保证数据的来源可靠性(确保是持有私钥的一方发送的)。但是,如果中间人伪造一堆公钥和私钥,将接收方原来的公钥替换为伪造的公钥。那么中间人就可以构造假报文,接收方通过被替换的假公钥正常解密,得到的却是伪造的假报文HTTPS 协议为了解决中间人冒充发送方的问题,采用了数字证书的方式。CA 数字证书认证机构可以利用私钥 (CA自己的私钥)制作数字证书(公钥 + CA的数字签名),所有 CA公钥都已经置入浏览器或者操作系统里面了。发送方将公钥交给 CA 数字证书认证机构生成数字证书,然后接收方收到消息之后,用浏览器/操作系统自带的 CA 公钥进行解密,确认服务器数字证书的真实性。如果解密成功且哈希值匹配,则从数字证书中提取发送方颁发的公钥,然后用公钥将报文加密进行传输。

HTTPS-数字证书

【HTTPS 建立连接过程】

HTTPS 相较于 HTTP 来说, 除了 TCP 三次握手之外,还多了 SSL/TLS 协议的握手阶段。TLS 握手阶段涉及四次通信,使用不同的密钥交换算法,一般常用 RSA 算法 和 ECDHE 算法。下面具体介绍基于 RSA 算法的 TLS 握手过程。TLS 协议建立的具体流程如下:

  1. ClientHello:首先,客户端向服务器发起加密通信请求 ClientHello。客户端会在这一步向服务器发送一下信息:

    • 客户端支持的 TLS 版本,比如 TLS 1.2
    • 客户端产生的随机数 C,后面用于生成会话密钥的条件之一
    • 客户端支持的密码套件列表,比如 RSA 加密算法
  2. ServerHello:服务器收到客户端请求之后,想客户端发出响应 ServerHello。服务器回应的内容如下:

    • 确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信
    • 服务器产生的随机数 S, 也是后面用于生成会话密钥的条件之一
    • 确认密码套件列表,比如 RSA 加密算法
    • 服务器的数字证书 (服务器向CA申请的)
  3. 客户端回应:客户端收到服务端的回之后,首先通过浏览器/操作系统中的 CA 公钥,对服务器的数字证书进行校验。如果证书没有问题,则取出数字证书中的服务器公钥,然后使用服务器的公钥加密报文,向服务器发送下面的信息:

    • 一个随机数 (pre-master key),该随机数会被客户端用服务器的公钥加密
    • 加密通信算法改变通知,表示随后的信息都将用会话密钥进行加密通信
    • 客户端握手结束通知,通知服务器表明客户端握手的阶段已经结束了

    【注意】 服务器和客户端都有了三个随机数 (客户端随机数 C、服务器随机数 Spre-master key)之后,通过协商的加密算法,计算出本次的通信的会话密钥

  4. 服务器的最后回应:服务器计算出会话密钥之后,向客户端发送最后的消息:

    • 加密通信算法改变通知,表示随后的消息都将用会话密钥加密通信
    • 服务器握手结束通知,通知客户端表明服务器握手的阶段结束了

HTTPS-建立连接过程