1 OSI 和 HTTP

1 OSI七层(TCP/IP)体系机构

TCP/IP 四层模型

  1. 应用层位于传输层之上,主要提供两个终端设备上的应用程序之间信息交换的服务,它定义了信息交换的格式,消息会交给下一层传输层来传输。 我们把应用层交互的数据单元称为报文。

  2. 传输层的主要任务就是负责向两台终端设备进程之间的通信提供通用的数据传输服务

  3. 网络层负责为分组交换网上的不同主机提供通信服务。

  4. 数据链路层的作用是将网络层交下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。每一帧包括数据和必要的控制信息(如同步信息,地址信息,差错控制等)。

    物理层的作用是实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异

img

1.1 如果缺少某一层会有什么后果?

1 为什么要有应用层,如果没有会怎么样?

根据应用层的作用来回答,比如:多样的应用层协议、同意传输格式、增加编码复杂性

  1. 无法实现多样化的网络服务:应用层协议如HTTP、FTP、SMTP等,都是为了满足特定的网络需求而设计的。如果没有应用层,用户将无法使用诸如Web浏览、文件传输、电子邮件发送等网络服务。
  2. 缺乏统一的数据交换标准:应用层协议为应用程序之间的数据交换提供了统一的标准。如果没有应用层,各种应用程序将需要自行定义数据交换格式和规则,这将导致混乱和不兼容性,使得不同应用程序之间的数据交换变得困难甚至不可能。
  3. 增加代码开发和维护的复杂性:如果没有应用层,网络开发人员将需要处理更多底层的细节和问题,这将增加开发和维护的复杂性。同时,由于缺乏统一的标准和协议,不同厂商和开发人员之间的协作将变得更加困难。

2 传输层的职责是什么,如果没有传输层会怎么样,可以直接通过ip进行通信吗?

根据运输层TCP的功能和实现可靠传输的途径来分析,没有可靠传输和没有采取这些途径会怎么样

可以直接通过IP,如ICMP报文

职责:传输层为应用层提供端到端的通信服务,负责数据的可靠传输或不可靠传输。在这一层,数据的单位称为段(segment)。

如果没有传输层会怎么样?

  1. 可靠性问题:没有传输层提供的差错控制和流量控制机制,数据在传输过程中可能会丢失、损坏或乱序到达,导致通信的可靠性大大降低。
  2. 效率问题:没有分段和重组功能,大数据传输可能会受到网络层对数据包大小的限制,导致传输效率低下。
  3. 应用程序复杂性增加:应用程序将需要自行处理数据分段、流量控制、差错控制等底层细节,增加了开发复杂性和维护成本。

可以直接通过ip进行通信吗?

可以直接通过IP进行通信 。但主要用于一些特定的网络诊断和底层协议开发等场景。在正常的网络通信中,我们一般不会直接使用IP进行通信,而是会使用更高层次的传输层协议(如TCP或UDP)。 例如:Ping操作也算是一种通过IP进行的通信。Ping命令主要测试计算机名和计算机的IP地址,验证与远程计算机的连接。它会向计算机发送ICMP(控制消息/错误报文协议)回应数据包,并等待这些数据包的返回时间,以校验与远程计算机或本地计算机的连接情况。在这个过程中,Ping命令直接使用了IP协议进行通信。

3 如果只通过ip完成通信,主机可以确定进行通信的是哪个进程吗?

不能,只能到达目的主机

如果只通过IP完成通信,主机无法确定进行通信的是哪个进程。因为IP层只负责将数据从源主机路由到目的主机,并不关心数据具体属于哪个进程。确定通信进程的任务是由传输层(如TCP或UDP)来完成的。传输层协议为每个进程分配一个唯一的端口号,通过这个端口号,主机就可以确定数据应该发送给哪个进程。

2 HTTP vs HTTPS

  • 端口号:HTTP 默认是 80,HTTPS 默认是 443。
  • URL 前缀:HTTP 的 URL 前缀是 http://,HTTPS 的 URL 前缀是 https://
  • 安全性和资源消耗:HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。HTTPS 是运行在 SSL/TLS 之上的 HTTP 协议,SSL/TLS 运行在 TCP 之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源。
  • SEO(搜索引擎优化):搜索引擎通常会更青睐使用 HTTPS 协议的网站,因为 HTTPS 能够提供更高的安全性和用户隐私保护。使用 HTTPS 协议的网站在搜索结果中可能会被优先显示,从而对 SEO 产生影响。

3 HTTP/1.0 vs HTTP/1.1

  • 连接方式 : HTTP/1.0 为短连接,HTTP/1.1 支持长连接。
  • 带宽:HTTP/1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP/1.1 则在请求头引入了 range 头字段,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  • HTTP流水线(管道机制):HTTP1.1支持管道传输,只要一个请求发出去,不需要等其回来,就可以发送第二个请求,减少整体的响应时间,但是可能造成队头阻塞。可以用于支持幂等性请求(如:GET、HEAD、DELETE、PUT等,不支持POST)。
  • Host 头(Host Header)处理 :HTTP/1.1 引入了 Host 头字段,允许在同一 IP 地址上托管多个域名,从而支持虚拟主机的功能。而 HTTP/1.0 没有 Host 头字段,无法实现虚拟主机。
  • 状态响应码 : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。
  • 缓存机制 : 在 HTTP/1.0 中主要使用 Header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP/1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。

4 HTTP/1.1 vs HTTP/2.0

  • 多路复用(Multiplexing):HTTP/2.0 的多路复用使得不同的请求可以共用一个 TCP 连接,避免建立多个连接带来不必要的额外开销,而 HTTP/1.1 中的每个请求都会建立一个单独的连接
    而浏览器为了控制资源会有 6-8 个 TCP 连接都限制。这使得 HTTP/2.0 在处理多个请求时更加高效,减少了网络延迟和提高了性能。
  • 二进制帧(Binary Frames):HTTP/2.0 使用二进制帧进行数据传输,而 HTTP/1.1 则使用文本格式的报文。二进制帧更加紧凑和高效,减少了传输的数据量和带宽消耗。
  • 头部压缩(Header Compression):HTTP/1.1 支持Body压缩,Header不支持压缩。HTTP/2.0 支持对Header压缩,使用了专门为Header压缩而设计的 HPACK 算法,在服务端和客户端建立头信息表,减少了网络开销。
  • 服务器推送(Server Push):HTTP/2.0 支持服务器推送,可以在客户端请求一个资源时,将其他相关资源一并推送给客户端,从而减少了客户端的请求次数和延迟。而 HTTP/1.1 需要客户端自己发送请求来获取相关资源。

5 HTTP/2.0 vs HTTP/3.0

  • 传输协议:HTTP/2.0 是基于 TCP 协议实现的,HTTP/3.0 改用 QUIC(Quick UDP Internet Connections) 协议来实现可靠的传输。
  • 连接建立:HTTP/2.0 建立安全连接https 需要 2.5 或 3.5 个 RTT)。HTTP/3.0 连接建立仅需 0-RTT 或者 1-RTT。这意味着 QUIC 在最佳情况下不需要任何的额外往返时间就可以建立新连接。
    • TCP 三次握手:客户端和服务器交换 SYN 和 ACK 包,建立一个 TCP 连接。这个过程需要 1.5 个 RTT(round-trip time),即一个数据包从发送到接收的时间。
    • TLS 握手:客户端和服务器交换密钥和证书,建立一个 TLS 加密层。这个过程需要至少 1 个 RTT(TLS 1.3)或者 2 个 RTT(TLS 1.2)。
    • HTTP/3.0中QUIC 协议(TLS 1.3,TLS 1.3 除了支持 1 个 RTT 的握手,还支持 0 个 RTT 的握手)
  • 队头阻塞:HTTP/2.0 多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。由于 QUIC 协议的特性,HTTP/3.0 在一定程度上解决了队头阻塞(Head-of-Line blocking, 简写:HOL blocking)问题,一个连接建立多个不同的数据流QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口。这些数据流之间独立互不影响,某个数据流发生丢包了,其数据流不受影响(本质上是多路复用+轮询)。
  • 错误恢复:HTTP/3.0 具有更好的错误恢复机制,当出现丢包、延迟等网络问题时,可以更快地进行恢复和重传。而 HTTP/2.0 则需要依赖于 TCP 的错误恢复机制。
http-3-implementation

6 WebSocket

WebSocket 是一种基于 TCP 连接的全双工通信协议,即客户端和服务器可以同时发送和接收数据。

6.1 WebSocket 和 HTTP 有什么区别?

WebSocket 和 HTTP 两者都是基于 TCP 的应用层协议,都可以在网络中传输数据。

下面是二者的主要区别:

  • WebSocket 是一种双向实时通信协议,而 HTTP 是一种单向通信协议。并且,HTTP 协议下的通信只能由客户端发起,服务器无法主动通知客户端。
  • WebSocket 使用 ws:// 或 wss://(使用 SSL/TLS 加密后的协议,类似于 HTTP 和 HTTPS 的关系) 作为协议前缀,HTTP 使用 http:// 或 https:// 作为协议前缀。
  • WebSocket 可以支持扩展,用户可以扩展协议,实现部分自定义的子协议,如支持压缩、加密等。
  • WebSocket 通信数据格式比较轻量,用于协议控制的数据包头部相对较小,网络开销小,而 HTTP 通信每次都要携带完整的头部,网络开销较大(HTTP/2.0 使用二进制帧进行数据传输,还支持头部压缩,减少了网络开销)。

6.2 WebSocket 的工作过程是什么样的?

WebSocket 的工作过程可以分为以下几个步骤:

  1. 想建立 WebSocket 连接,就会在 HTTP 请求里带上一些特殊的header 头,如下:

    1
    2
    3
    Connection: Upgrade
    Upgrade: WebSocket
    Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
  2. 如果服务器正好支持升级成 WebSocket 协议。就会走 WebSocket 握手流程,同时根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,放在 HTTP 响应的 Sec-WebSocket-Accept 头里,同时带上101状态码,发回给浏览器。HTTP 的响应如下:

    1
    2
    3
    4
    HTTP/1.1 101 Switching Protocols\r\n
    Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
    Upgrade: WebSocket\r\n
    Connection: Upgrade\r\n
  3. 客户端和服务器之间建立了一个 WebSocket 连接,可以进行双向的数据传输。数据以帧(frames)的形式进行传送,WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完整的消息。

  4. 客户端或服务器可以主动发送一个关闭帧,表示要断开连接。另一方收到后,也会回复一个关闭帧,然后双方关闭 TCP 连接。

另外,建立 WebSocket 连接之后,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性。

6.3 WebSocket的消息格式

数据包在WebSocket中被叫做
图片

  • opcode字段:这个是用来标志这是个什么类型的数据帧。比如:
    • 等于 1 ,是指text类型(string)的数据包
    • 等于 2 ,是二进制数据类型([]byte)的数据包
    • 等于 8 ,是关闭连接的信号
  • payload字段:存放的是我们真正想要传输的数据的长度,单位是字节。比如你要发送的数据是字符串"111",那它的长度就是3
    • 有多个payload字段,从前往后读取,若第一个payload表示的长度不够,就读下一个更长的payload,以此类推

6.3 WebSocket 与 SSE 有什么区别?

SSE 与 WebSocket 作用相似,都可以建立服务端与浏览器之间的通信,实现服务端向客户端推送消息,但还是有些许不同:

  • SSE 是基于 HTTP 协议的,它们不需要特殊的协议或服务器实现即可工作;WebSocket 需单独服务器来处理协议。
  • SSE 单向通信,只能由服务端向客户端单向通信;WebSocket 全双工通信,即通信的双方可以同时发送和接受信息。
  • SSE 实现简单开发成本低,无需引入其他组件;WebSocket 传输数据需做二次解析,开发门槛高一些。
  • SSE 默认支持断线重连;WebSocket 则需要自己实现。
  • SSE 只能传送文本消息,二进制数据需要经过编码后传送;WebSocket 默认支持传送二进制数据和文本数据。

SSE 与 WebSocket 该如何选择?

  • WebSocket:双向、全双工通信。对于游戏、即时通信以及需要双向近乎实时更新的场景。
  • SSE:不需要从客户端发送数据。而你只需要一些服务器操作的更新。比如:站内信、未读消息数、状态更新、股票行情、监控数量等场景,SEE 不管是从实现的难易和成本上都更加有优势。此外,SSE 具有 WebSocket 在设计上缺乏的多种功能,例如:自动重新连接、事件 ID 和发送任意事件的能力。

2 TCP

1 TCP 与 UDP 的区别

  1. 是否面向连接:UDP 在传送数据之前不需要先建立连接。而 TCP 提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接。
  2. 是否是可靠传输:远地主机在收到 UDP 报文后,不需要给出任何确认,并且不保证数据不丢失,不保证是否顺序到达。TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。
  3. 是否有状态:这个和上面的“是否可靠传输”相对应。TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了(这很渣男!)。
  4. 传输效率:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多。
  5. 传输形式:TCP 是面向字节流的,UDP 是面向报文的。
  6. 首部开销:TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大。
  7. 是否提供广播或多播服务:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
TCPUDP
是否面向连接
是否可靠
是否有状态
传输效率较慢较快
传输形式字节流数据报文段
首部开销20 ~ 60 bytes8 bytes
是否提供广播或多播服务

UDP 一般用于即时通信,比如:语音、 视频、直播等等。这些场景对传输数据的准确性要求不是特别高,比如你看视频即使少个一两帧,实际给人的感觉区别也不大。

TCP 用于对传输准确性要求特别高的场景,比如文件传输、发送和接收邮件、远程登录等等。

2 TCP 延迟确认机制

当发送没有携带数据的 ACK,它的网络效率也是很低的,因为它也有 40 个字节的 IP 头 和 TCP 头,但却没有携带数据报文。 为了解决 ACK 传输效率低问题,所以就衍生出了 TCP 延迟确认。 TCP 延迟确认的策略:

  • 当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方
  • 当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送,达到最大延迟确认时间后 进行ACK发送
  • 如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK

3 TCP连接的建立与断开

3.1 三报文握手

image-20201022202932905

三次握手建立连接的首要目的是「同步序列号」。

为什么不能使用两报文握手?

  • 为了告诉客户端:“我接收到的信息确实就是你所发送的信号了”,这表明从客户端到服务端的通信是正常的。
  • 为了防止已失效的连接请求报文段突然又传送到了TCP服务器,若是两次握手,服务器发送SYN+ACK后,服务端以为已经建立连接而发生无效等待,但是客户端是没有理睬服务端的第二次握手的

3.2 四报文挥手

image-20231023095232736

为什么要进入TIME-WAIT状态?

  • 因为时间等待状态以及处于该状态2MSL时长,可以确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态
  • 另外,TCP客户进程在发送完最后一个TCP确认报文段后,在经过2MSL时长,就可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的TCP连接中,不会出现旧连接中的报文段

注意一件事:

  1. 挥手可由任意一方发起,各方状态也应该相应匹配,上图是由客户端主动发起的,客户端为主动方。
  2. 所以当服务端为主动方时,服务端也会出现TIME-WAIT状态

3.3 粗暴关闭 vs 优雅关闭

关闭的连接的函数有两种函数:

  • close 函数(粗暴关闭)
    • socket 同时关闭发送方向和读取方向,也就是 socket 不再有发送和接收数据的能力。如果有多进程/多线程共享同一个 socket,如果有一个进程调用了 close 关闭只是让 socket 引用计数 -1,并不会导致 socket 不可用,同时也不会发出 FIN 报文,其他进程还是可以正常读写该 socket,直到引用计数变为 0,才会发出 FIN 报文
    • 适用于服务端
    • 调用close关闭的一方,由于不能收发数据,所以被称为孤儿连接
  • shutdown 函数(优雅关闭)
    • socket 可以指定只关闭读方向或写方向,也就是 socket 不再有发送(接收)数据的能力,但是还是具有接收(发送)数据的能力。如果有多进程/多线程共享同一个 socket,shutdown 则不管引用计数,直接使得该 socket 不可用,然后发出 FIN 报文,如果有别的进程企图使用该 socket,将会受到影响。
    • 适用于客户端的FIN-WAIT-1,关闭写方向(所以发送FIN),保留读方向

3.4 保活计时器(TCP的Keepalive保活机制)

  • TCP服务器进程每收到一次TCP客户进程的数据,就重新设置并启动保活计时器(2小时定时)
  • 若保活计时器定时周期内未收到TCP客户进程发来的数据,则当保活计时器到时后,TCP服务器进程就向TCP客户进程发送一个探测报文段,以后则每隔75秒钟发送一次。若一连发送10个探测报文段后仍无TCP客户进程的响应,TCP服务器进程就认为TCP客户进程所在主机出了故障,接着就关闭这个连接。

在应用程序中需要通过 SO_KEEPALIVE 参数进行开启TCP保活机制

注意与HTTP Keep-Alive (HTTP长连接)加以区分

3.5 四报文挥手有可能合并第二和第三次挥手吗?

即客户端发送FIN(第一次)后,服务端回应ACK+FIN(第二次),最后客户端发送ACK(第三次)

可能的,需要满足两个条件:

  1. 服务端没有数据要发送了
  2. 开启了TCP延迟确认机制

当服务端接收到FIN后,需要回复一个ACK,但是因为TCP延迟确认机制,自动等待有数据要发送时一起回传,但是服务端没有数据要发送了,所以服务端发送FIN,FIN也是数据,所以前面等待的ACK就和FIN一起回传了,就形成了三次挥手

3.6 服务端与客户端进行TCP连接的流程

服务端伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
/*Step 1: 创建服务器端监听socket描述符listen_fd*/
listen_fd = socket(AF_INET, SOCK_STREAM, 0);

/*Step 2: bind绑定服务器端的IP和端口,所有客户端都向这个IP和端口发送和请求数据*/
bind(listen_fd, xxx);

/*Step 3: 服务端开启监听*/
listen(listen_fd, 128);

/*Step 4: 服务器等待客户端的链接,返回值cfd为客户端的socket描述符*/
cfd = accept(listen_fd, xxx);

/*Step 5: 读取客户端发来的数据*/
n = read(cfd, buf, sizeof(buf));
}

客户端伪代码:

1
2
3
4
5
6
7
8
9
10
11
int main()
{
/*Step 1: 创建客户端端socket描述符cfd*/
cfd = socket(AF_INET, SOCK_STREAM, 0);

/*Step 2: connect方法,对服务器端的IP和端口号发起连接*/
ret = connect(cfd, xxxx);

/*Step 4: 向服务器端写数据*/
write(cfd, buf, strlen(buf));
}

服务端进行listen后,客户端发起connet进行连接,然后就会进行三报文握手

3.7 半连接队列与全连接队列

半连接队列和全连接队列
  • 半连接队列(SYN队列),服务端收到第一次握手后,会将sock加入到这个队列中,队列内的sock都处于SYN_RECV 状态。
  • 全连接队列(ACCEPT队列),在服务端收到第三次握手后,会将半连接队列的sock取出,放到全连接队列中。队列里的sock都处于 ESTABLISHED状态。这里面的连接,就等着服务端执行accept()后被取出了。

其中全连接队列(icsk_accept_queue)是个链表,而半连接队列(syn_table)是个哈希表

为什么?

  • 全连接队列存放的是已经建立完成的连接,这些连接正等待被取走。服务端取走连接的过程中,并不关心具体是哪个连接,直接从队列头取就行了。这个过程算法复杂度为O(1)
  • 半连接队列存放的都是不完整的连接,等待着第三次握手的到来。第三次握手来了,需要从队列里把相应IP端口的连接取出,使用哈希表能快速定位到取出的位置,算法复杂度就是O(1),否则使用链表复杂度就是O(n)。

队列的长度默认值:

  • 半连接:Linux内核参数:tcp_max_syn_backlog(默认1024)
  • 长连接/Accept:min(somaxconn, backlog)
    • Linux内核参数:somaxconn(默认128);Web服务器参数(例如Tomcat、Nginx、Apache):backlog(通常默认511)

3.8 SYN 报文什么时候情况下会被丢弃?

  1. 开启 tcp_tw_recycle 参数,并且在 NAT 环境下,造成 SYN 报文被丢弃(此参数已被废弃,慎用,建议关闭)
  2. 一般情况下,TCP 两个连接队列满了(半连接队列和全连接队列),造成 SYN 报文被丢弃

例如:

  • 开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接
  • 将 tcp_abort_on_overflow 参数设置为 1,可以在accept 队列已满时择向客户端发送 RST 复位报文,通知连接废弃

syncookies 参数主要有以下三个值:

  • 0 值,表示关闭该功能;
  • 1 值,表示仅当 SYN 半连接队列放不下时,再启用它;
  • 2 值,表示无条件开启功能;

tcp_abort_on_overflow 共有两个值分别是 0 和 1,其分别表示:

  • 0 :如果 accept 队列满了,那么 server 扔掉 client 发过来的 ack ;
  • 1 :如果 accept 队列满了,server 发送一个 RST 包给 client,表示废掉这个握手过程和这个连接;

有些时候不推荐设置位1,因为可能accept队列空出来了,就能成功建立连接

3.9 服务端没有listen或没有accept能建立连接吗?

  • 没有listen
    • 没有listen不能建立连接,因为listen过后才开始三报文握手,服务端没有listen时收到客户端的SYN请求会回传一个RST 报文
  • 没有accept
    • 建立连接的过程中根本不需要accept()参与, 执行accept()只是为了从全连接队列里取出一条连接。

3.10 因为网络原因第三次挥手比数据包先到达会如何处理?

在 FIN_WAIT_2 状态时,如果收到乱序的 FIN 报文,那么就被会加入到「乱序队列」,并不会进入到 TIME_WAIT 状态。

等再次收到前面被网络延迟的数据包时,会判断乱序队列有没有数据,然后会检测乱序队列中是否有可用的数据,如果能在乱序队列中找到与当前报文的序列号保持的顺序的报文,就会看该报文是否有 FIN 标志,如果发现有 FIN 标志,这时才会进入 TIME_WAIT 状态。

3.11 HTTPS连接的建立 / TLS握手

img

HTTPS需要先在内核态进行TCP握手,然后才能在应用层实现TLS的握手,所以TCP握手时消息是明文,有安全问题,通过随机初始seq序列号来提高一定的安全性,但是不能防止消息被截获

  1. 第一次握手:

    • Client Hello:发送客户端自己的TLS版本号,支持的密码套件列表,以及随机数Client Random;这个随机数会被服务端保留,它是生成对称加密密钥的材料之一。
  2. 第二次握手:

    • Server Hello:确认TLS版本号,选择一个密码套件,生成随机数Server Random
    • Server Certificate:发送服务器使用的证书给客户端证明自己的身份
    • [(密钥交换算法使用ECDHE算法时)Server Key Exchange:生成 服务端的椭圆曲线公钥 发送给客户端]
    • Server Hello Done:本次打招呼完毕

    这里客户端会验证证书是否有效:

    先将证书的内容使用哈希算法进行哈希得到hash1,再将证书上的 证书签名 使用公钥解密后得到hash12,对比两个hash是否相等

  3. 第三次握手:

    • Client Key Exchange:客户端生成新的随机数pre-master,使用RSA公钥加密后发送给服务端,服务端收到后使用自己的RSA私钥进行解密,就得到了对称加密的密钥
      • [若为ECDHE算法:生成 客户端的椭圆曲线公钥 发给服务端。]
    • Change Cipher Spec:通知服务端之后开始使用加密方式发送消息。
    • Encrypted Handshake Message(Finishd):把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信「是否可用」和「之前握手信息是否有被中途篡改过」。
  4. 第四次握手:

    • Change Cipher Spec:通知客户端之后开始使用加密方式发送消息。
    • Encrypted Handshake Message(Finishd):把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信「是否可用」和「之前握手信息是否有被中途篡改过」。

TLS1.2连接的建立需要2个RTT,而TLS1.3连接的建立缩短到1个RTT,一般情况下,TCP的第三次握手可与TLS的第一次握手合并

所以HTTPS连接的建立一般需要 2.5 ~ 3.5个RTT,若合并一次握手,则需要2 ~ 3个RTT

3.12 Fast Open

用于进行过一次通话后,快速建立连接,而无需再次三次握手:

tcp_fastopn 各个值的意义:

  • 0 关闭
  • 1 作为客户端使用 Fast Open 功能
  • 2 作为服务端使用 Fast Open 功能
  • 3 无论作为客户端还是服务器,都可以使用 Fast Open 功能

TCP Fast Open 功能需要客户端和服务端同时支持,才有效果

image-20240312230621374

3.13 什么情况下HTTPS中TLS和TCP能同时握手?

需要下面这两个条件同时满足才可以:

  • 客户端和服务端都开启了 TCP Fast Open 功能,且 TLS 版本是 1.3;
  • 客户端和服务端已经完成过一次通信;

客户端和服务端同时支持 TCP Fast Open 功能的情况下,在第二次以后到通信过程中,客户端可以绕过三次握手直接发送数据,而且服务端也不需要等收到第三次握手后才发送数据。

如果 HTTPS 的 TLS 版本是 1.3,那么 TLS 过程只需要 1-RTT。

因此如果「TCP Fast Open + TLSv1.3」情况下,在第二次以后的通信过程中,TLS 和 TCP 的握手过程是可以同时进行的。

如果基于 TCP Fast Open 场景下的 TLSv1.3 0-RTT 会话恢复过程,不仅 TLS 和 TCP 的握手过程是可以同时进行的,而且 HTTP 请求也可以在这期间内一同完成。

图片

4 TCP可靠传输的保障

  1. 基于数据块传输:应用数据被分割成 TCP 认为最适合发送的数据块
  2. 对失序数据包重新排序以及去重:使用seq序列号进行去重和排序
  3. **校验和(差错检测)**:如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段
  4. **重传机制(自动请求重传协议ARQ)**:数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答
  5. 流量控制:TCP 使用的流量控制协议是可变大小的滑动窗口协议(TCP 利用滑动窗口实现流量控制)。
  6. 拥塞控制:TCP 在发送数据的时候,需要考虑两个因素:一是接收方的接收能力,二是网络的拥塞程度。四个算法:慢开始、拥塞避免、快重传、快恢复

超时重传时间的选择:
image-20201022154418863

5 如何理解TCP是面向字节流,而UDP是面向报文的?

  • 当用户消息通过 UDP 协议传输时,操作系统不会对消息进行拆分,在组装好 UDP 头部后就交给网络层来处理,所以发出去的 UDP 报文中的数据部分就是完整的用户消息,也就是每个 UDP 报文就是一个用户消息的边界,这样接收方在接收到 UDP 报文后,读一个 UDP 报文就能读取到完整的用户消息。(区分多个UDP报文:插入到队列里)
  • 当用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个的 TCP 报文,也就是一个完整的用户消息被拆分成多个 TCP 报文进行传输。我们不能认为一个用户消息对应一个 TCP 报文,正因为这样,所以 TCP 是面向字节流的协议。接收方的程序如果不知道发送方发送的消息的长度,也就是不知道消息的边界时,是无法读出一个有效的用户消息的。

粘包与拆包的产生:

  • 当两个消息的某个部分内容被分到同一个 TCP 报文时,就是我们常说的 TCP 粘包问题,这时接收方不知道消息的边界的话,是无法读出有效的消息。
  • 对应的,当一条消息的某个部分被分到了其它的TCP报文时,就是我们常说的 TCP 拆包问题

在Netty中的体现:

  1. 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包
  2. 进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度**>MSS的时候将发生拆包**。
  3. 应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包
  4. 接收方法不及时读取套接字缓冲区数据,这将发生粘包

6 粘包与拆包的解决方式

粘包与拆包 的问题出现是因为不知道一个用户消息的边界在哪,如果知道了边界在哪,接收方就可以通过边界来划分出有效的用户消息。

一般有三种方式分包的方式:

  1. 固定长度的消息;
  2. 特殊字符作为边界;
    • 例如:HTTP 通过设置 回车符/换行符 作为 HTTP 报文协议 header与body的边界。
  3. 自定义消息结构:
    • 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

Netty的粘包/拆包是怎么处理的,有哪些实现?

对于粘包和拆包问题,常见的解决方案有四种:

  1. 客户端在发送数据包的时候,每个包都固定长度,比如1024个字节大小,如果客户端发送的数据长度不足1024个字节,则通过补充空格的方式补全到指定长度;Netty提供的FixedLengthFrameDecoder
  2. 客户端在每个包的末尾使用固定的分隔符,例如rn,如果一个包被拆分了,则等待下一个包发送过来之后找到其中的rn,然后对其拆分后的头部部分与前一个包的剩余部分进行合并,这样就得到了一个完整的包;Netty提供DelimiterBasedFrameDecoder与LineBasedFrameDecoder(实现类)
  3. 将消息分为头部和消息体,在头部中保存有当前整个消息的长度,只有在读取到足够长度的消息之后才算是读到了一个完整的消息;Netyy提供了LengthFieldBasedFrameDecoder与LengthFieldPrepender
  4. 通过自定义协议进行粘包和拆包的处理。Netty提供了通过实现MessageToByteEncoderByteToMessageDecoder

还有一种不规范的编解码:不依赖于上面四种方法提供的编解码器,而是依赖于ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter,在处理器InboundHandler中,拿到消息时对消息进行解码;在OutboundHandler对消息进行编码,这样就可以使用我们已有的协议类型,比如WebSocket协议的TextWebSocketFrame,因为自带payLoad字段作为长度标识,所以我们可以直接获取WS帧的数据部分

7 如何优化TCP

以三个角度来阐述提升 TCP 的策略,分别是:

  • TCP 三次握手的性能提升;
  • TCP 四次挥手的性能提升;
  • TCP 数据传输的性能提升;
  1. TCP 三次握手的性能提升;
    • 客户端优化:
      • 调整客户端重发SYN请求的次数,由 tcp_syn_retries 参数控制,默认是 5 次;第一次超时重传是在 1 秒后,每次超时的时间是上一次的 2 倍。客户端重传达到上限就会终止握手。
    • 服务端优化:
      • 增大半连接队列和全连接队列的长度, 需要同时增大Linux内核参数:tcp_max_syn_backlog(默认1024)、somaxconn(默认128);Web服务器参数(例如Tomcat、Nginx、Apache):backlog(通常默认511)
      • 开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接
        • 0 值,表示关闭该功能;
        • 1 值,表示仅当 SYN 半连接队列放不下时,再启用它;
        • 2 值,表示无条件开启功能;
      • 调整服务端重发SYN+ACK的次数的,由 tcp_synack_retries 参数控制,默认是 5 次,和客户端类似
      • accept 队列已满,丢弃连接只是 Linux 的默认行为,我们还可以选择向客户端发送 RST 复位报文,告诉客户端连接已经建立失败。打开这一功能需要将 tcp_abort_on_overflow 参数设置为 1;若为 0 表示丢弃连接
      • 开启 Fast Open 绕过三次握手
  2. TCP 四次挥手的性能提升;
    • 主动关闭方的优化:
      • 调整主动发重发FIN的次数,由 tcp_orphan_retries 参数控制,默认值是0(但是设为0时,默认情况是重试8次);避免对方没收到消息一直处于FIN-WAIT1状态
      • 调整 tcp_max_orphans 参数,设置「孤儿连接」(调用close函数后即为孤儿连接)的最大数量。如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送 RST 复位报文强制关闭。
      • 调整 tcp_fin_timeout 参数,控制孤儿连接FIN-WAIT2状态下最大持续时长,默认值是 60 秒。如果在 60 秒后还没有收到 FIN 报文,连接就会直接关闭。
      • TIME-WAIT优化:
        • 调整 tcp_max_tw_buckets 参数,当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历 TIME_WAIT 而直接关闭。
        • 打开 tcp_tw_reuse 参数,复用客户端处于 TIME_WAIT 状态的连接,因为tcp_tw_reuse 只作用在 connect 函数,也就是客户端
    • 被动关闭方的优化:
      • 也是 tcp_orphan_retries 参数,该参数还可以控制 第三次 挥手的重传次数
  3. 数据传输的性能提升:
    • 扩大窗口大小 tcp_window_scaling
    • 调整发送和接收缓冲区的范围,打开接收缓冲区动态调节功能,tcp_wmem,tcp_rmem,tcp_moderate_rcvbuf
    • 调节 TCP 内存范围,tcp_mem

8 TCP的缺点

  1. TCP协议的升级工作很困难

    • TCP协议是在内核中实现的,当我们升级内核后,需要服务端和客户端都 支持/兼容 新版本内核才能使用TCP的新特性,所有客户端和服务端的升级成本是很高的
  2. TCP 建立连接的延迟

    • TCP连接的建立具有1.5个RTT的时延,而HTTPS具有2.5~3.5个RTT的时延,时延太高,虽然能够通过Fast Open改善,但并不是所有操作系统都支持(即TCP的升级很困难)
  3. TCP 存在队头阻塞问题

    • TCP是有序的,当发生丢包时,会使后面的seq发生阻塞;直到 HTTP3.0 才一定程度上解决了队头阻塞问题,但是HTTP3.0使用的是QUIC协议,并非TCP协议
  4. 网络变化时 需要重新建立 TCP 连接

    • 基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。重新建立连接是有时延和成本的。
    • 例如当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立 TCP 连接。

9 常见的网络攻击?如何应对SYN flood攻击?

下面攻击中,有多种是属于DDos(分布式拒绝服务)攻击

  • SYN Flood攻击:这是一种利用TCP协议握手过程中的缺陷进行的攻击。攻击者发送大量的TCP SYN请求到目标服务器,但在收到服务器的SYN+ACK响应后并不发送最后的ACK确认,导致服务器上留下大量等待完成的半开连接,耗尽服务器资源,使得正常的TCP连接无法建立。(DDos)
  • TCP会话劫持:这种攻击方式是通过窃取TCP会话中的序列号等信息,然后冒充合法用户接入到会话中。攻击者可以监听网络上的TCP会话,分析并预测序列号,然后发送伪造的数据包,中断或篡改原有的会话内容。
  • TCP重置攻击: 在这种攻击中,攻击者发送伪造的TCP RST(重置)数据包到目标主机,中断正常的TCP连接。由于TCP协议的设计,当接收到RST数据包时,连接的两端都会关闭连接,这使得攻击者可以成功地中断服务或进行拒绝服务攻击。
  • IP欺骗技术:当合法用户同服务器建立正常的连接后,伪装成这台主机的IP地址,并向服务器发送一个带有 RST 位的 TCP 数据段。服务器接收到这样的数据后,认为从 该主机 发送的连接有错误,就会清空缓冲区中建立好的连接。
  • UDP Flood攻击
  • SQL注入攻击

如何应对SYN flood攻击?

  1. 启用SYN Cookie技术:SYN Cookie是一种无状态的TCP连接技术,它通过计算一个独特的Cookie来验证TCP连接的合法性,而不需要在服务器上保存每个连接的状态信息。当服务器收到SYN请求时,它会计算一个Cookie并发送给客户端,客户端在后续的ACK报文中携带该Cookie,服务器通过验证Cookie的有效性来判断连接是否合法。这样可以有效减少服务器资源的消耗,并防止SYN flood攻击导致的资源耗尽,开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接。
  2. 调整TCP协议栈参数:通过调整TCP协议栈的参数,可以优化服务器的性能和防御SYN flood攻击。例如,可以减小SYN Timeout时间,使服务器更快地释放无效的连接请求;增大TCP连接的队列长度,提高服务器处理连接请求的能力;启用TCP Fast Open等特性,加快TCP连接的建立过程。
  3. 使用防火墙或入侵检测系统(IDS):防火墙或IDS可以监控网络流量,并识别出异常的SYN请求流量。它们可以根据预设的规则对恶意流量进行过滤或限制,从而保护服务器免受SYN flood攻击的侵害。

10 服务器中存在大量TIME_WAIT状态应该怎么排查?

如何排查TIME_WAIT

  1. 确认TIME_WAIT状态的数量: 使用netstat命令来查看当前TCP连接的状态分布。例如,运行netstat -nat | grep TIME_WAIT | wc -l可以查看TIME_WAIT状态的连接数。
  2. 查看系统TCP参数: 使用sysctl -a | grep tcp命令可以查看系统中与TCP相关的内核参数设置,特别关注net.ipv4.tcp_tw_reusenet.ipv4.tcp_tw_recycle(在某些情况下可能不推荐启用)和net.ipv4.tcp_fin_timeout等参数的设置。
  3. 分析网络连接和应用程序行为: 确定哪些应用程序或服务正在产生大量的TIME_WAIT连接。使用netstat -natp可以查看每个连接的进程ID和程序名称。
  4. 检查网络问题和延迟: 网络问题或延迟可能导致连接不能正常关闭,从而产生大量的TIME_WAIT状态。使用网络诊断工具(如pingtraceroute等)来检查网络状况。

11 TCP 和 UDP首部格式

一共11个字段:源端口、目的端口、seq序列号、ACK号、首部长度、保留字段、SYN等标志位、窗口大小、校验和、紧急指针、可选项扩展

alt

12 一个进程和一台机器理论上能创建多少条TCP连接?

  • 如果在不考虑服务器的内存和文件句柄资源的情况下,理论上一个服务端进程最多能支持约为 248 次方(2^32 (ip数) * 2^16 (端口数),约等于两百多万亿!
  • 而一台服务器有2^16次方端口,所以一台服务器理论上可以 2^32 (ip数) * 2^16 (端口数) * 2^16 (服务器端口数)

但是 Linux每维护一条TCP连接都要花费内存资源的,每一条静止状态(不发送数据和不接收数据)的 TCP 连接大约需要吃 3.44K 的内存,进行发送数据和接收数据还会额外消耗更多的内存资源

13 TCP、UDP端口冲突问题

TCP和UDP能使用同一个端口吗?

可以的

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

多个 TCP 服务进程可以同时绑定同一个端口吗?

  • 如果两个 TCP 服务进程同时绑定的 IP 地址和端口都相同,那么执行 bind() 时候就会出错,错误是“Address already in use”。
  • 如果两个 TCP 服务进程绑定的端口都相同,而 IP 地址不同,那么执行 bind() 不会出错。

客户端的端口可以重复使用吗?

只要四元组(源IP地址,源端口,目的IP地址,目的端口)中有一个不同,就可以就能重复使用

14 tcp_tw_reuse和tcp_tw_recycle为什么是默认关闭的?

什么是tcp_tw_reuse和tcp_tw_recycle?

  • net.ipv4.tcp_tw_reuse,如果开启该选项的话,客户端(连接发起方) 在调用 connect() 函数时,如果内核选择到的端口,已经被相同四元组的连接占用的时候,就会判断该连接是否处于 TIME_WAIT 状态,如果该连接处于 TIME_WAIT 状态并且 TIME_WAIT 状态持续的时间超过了 1 秒,那么就会重用这个连接,然后就可以正常使用该端口了。所以该选项只适用于连接发起方。
  • net.ipv4.tcp_tw_recycle,如果开启该选项的话,允许处于 TIME_WAIT 状态的连接被快速回收,该参数在 NAT 的网络下是不安全的

其实这题在变相问「如果 TIME_WAIT 状态持续时间过短或者没有,会有什么问题?

然后就考虑到 TIME_WAIT 状态的作用

  1. 让网络中残留的报文消失:历史 RST 报文可能会终止后面相同四元组的连接,因为 PAWS 检查到即使 RST 是过期的,也不会丢弃。
  2. 确保服务端正常关闭:如果第四次挥手的 ACK 报文丢失了,有可能被动关闭连接的一方不能被正常的关闭;

15 数据包在网络中的发送过程

一个数据包,从聊天框里发出,消息会从聊天软件所在的用户空间拷贝到内核空间发送缓冲区(send buffer),数据包就这样顺着传输层、网络层,进入到数据链路层,在这里数据包会经过流控(qdisc),再通过RingBuffer发到物理层的网卡。数据就这样顺着网卡发到了纷繁复杂的网络世界里。这里头数据会经过n多个路由器和交换机之间的跳转,最后到达目的机器的网卡处。

此时目的机器的网卡会通知DMA将数据包信息放到RingBuffer中,再触发一个硬中断CPUCPU触发软中断ksoftirqdRingBuffer收包,于是一个数据包就这样顺着物理层,数据链路层,网络层,传输层,最后从内核空间拷贝到用户空间里的聊天软件里。

网络发包收包全景图

16 TCP什么时候会发生数据丢失?

数据包发送和接收什么时候可能会丢包?

  1. TCP连接建立时:当连接队列满时,可能丢包
  2. 流量控制丢包:当发送数据过快,流控队列长度txqueuelen又不够大时,就容易出现丢包现象。
  3. 网卡丢包:
    1. RingBuffer过小导致丢包:在接收数据时,会将数据暂存到RingBuffer接收缓冲区中,然后等着内核触发软中断慢慢收走。如果这个缓冲区过小,而这时候发送的数据又过快,就有可能发生溢出,此时也会产生丢包
    2. 网卡性能不足
  4. 接收缓冲区丢包:接收缓冲区tcp_rmem 满,接收窗口为0,正在网络中的数据包将丢失
  5. 网络环境丢包:网络环境不好时,使用pingmtr -r [ip/域名]检测网络丢包率

使用TCP,因为有可靠传输,只能保证两端传输层之间不会发生数据丢失,但是传输层之上,TCP就不能保证了:

当TCP接收缓冲区接收到数据,并发送ACK后,应用从接收缓冲区读出数据后,还未来得及处理,就发生故障,就会出现数据丢失

怎么处理应用层丢包?

与发送方或者中间服务器进行一个最新消息的对比,若不一致则进行一个重新发送

3 IP层和数据链路层

1 地址解析协议ARP

ARP是数据链路层协议,当主机发送 IP 数据报文时(网络层),仅知道目的地的 IP 地址,并不清楚目的地的 MAC 地址,我们使用ARP协议来根据IP地址获取设备的MAC地址

ARP 工作原理:ARP 表、广播问询、单播响应

  1. ARP 表记录了某些其他网络设备的 IP 地址-MAC 地址映射关系,该映射关系以 <IP, MAC, TTL> 三元组的形式存储。其中,TTL 为该映射关系的生存周期,典型值为 20 分钟,超过该时间,该条目将被丢弃。
  2. 同一局域网内的 MAC 寻址:
    • 源主机发送ARP广播请求,目的MAC地址为FF-FF-FF-FF-FF-FF,目的主机接收到发给自己IP的请求后,将源主机的IP和MAC映射添加到自己的ARP表,然后单播发回ARP响应分组
  3. 不同局域网内的 MAC 寻址:
    • 源主机发送ARP广播请求,目的MAC地址为FF-FF-FF-FF-FF-FF,目标路由器接收到可以转发到对应子网的请求后,将路由器目的接口的IP和MAC映射添加到自己的ARP表,然后单播发回ARP响应分组

2 IPv6 vs IPv4

  • 更大的地址空间
  • 无状态地址自动配置(Stateless Address Autoconfiguration,简称 SLAAC):主机可以直接通过根据接口标识和网络前缀生成全局唯一的 IPv6 地址,而无需依赖 DHCP(Dynamic Host Configuration Protocol)服务器,简化了网络配置和管理。
  • NAT(Network Address Translation,网络地址转换) 成为可选项:IPv6 地址资源充足,可以给全球每个设备一个独立的地址。
  • 对标头结构进行了改进:IPv6 标头结构相较于 IPv4 更加简化和高效,减少了处理开销,提高了网络性能。
  • 可选的扩展头:允许在 IPv6 标头中添加不同的扩展头(Extension Headers),用于实现不同类型的功能和选项。
  • ICMPv6(Internet Control Message Protocol for IPv6):IPv6 中的 ICMPv6 相较于 IPv4 中的 ICMP 有了一些改进,如邻居发现、路径 MTU 发现等功能的改进,从而提升了网络的可靠性和性能。

4 其它常见问题

1 cookie、session和token的区别?各自的使用场景?

  • Cookie是由服务器创建后发送到用户浏览器并存储在客户端的小段数据。Cookie 一般用来保存用户信息。然而,由于Cookie存储在客户端,存在安全风险,如跨站请求伪造(CSRF)和跨站脚本攻击(XSS)。因此,它适用于非敏感信息的短期存储
  • Session是在服务器端创建并保存的用户会话信息。用于在服务端记录用户的状态,通过唯一的会话标识符(通常存储在Cookie中)与用户关联。这提供了更高的安全性,因为敏感数据不会传输到客户端。Session适用于需要维护用户状态和进行身份验证的Web应用程序,如登录状态和用户个人资料。
  • Token是一种身份验证和授权机制,通常用于API和微服务之间的通信。与Cookie和Session不同,Token是无状态的,意味着服务器不需要维护用户会话信息。相反,客户端在每次请求时附带Token,服务器验证其有效性并授权访问资源。常见的Token类型包括JWT

三者之间的联系:Token一般存放在Cookie中,经加密后发送到服务端进行解密,根据token解析出用户后将用户状态保存在Session中。

end