1. HTTP状态码

  • 1xx 提示信息,是协议处理中的一种中间状态,实际用到的比较少。

  • 2xx 表示服务器成功处理了客户端的请求。

    • 200 OK 表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。

    • 204 No Content 与 200 OK 基本相同,但响应头没有 body 数据。

    • 206 Partial Content 是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。

  • 3xx 表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。

    • 301 Moved Permanently 表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
    • 302 Found 表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。301 和 302 都会在响应头里使用字段 Location ,指明后续要跳转的 URL,浏览器会自动重定向新的URL。
    • 304 Not Modified 不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
  • 4xx 表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。

    • 400 Bad Request 表示客户端请求的报文有错误,但只是个笼统的错误。
    • 403 Forbidden 服务器禁止访问资源
    • 404 Not Found 请求的资源在服务器上不存在或未找到
  • 5xx 表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。

    • 500 Internal Server Error 与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。

    • 501 Not Implemented 表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思

    • 502 Bad Gateway 通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。

      503 Service Unavailable 网络服务正忙,请稍后重试

2. HTTP/1.1、HTTP/2、HTTP/3

  • HTTP/1.1 相比 HTTP/1.0 性能上的改进
    • 使用 TCP 长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
    • 支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间
  • HTTP/2 相比 HTTP/1.1 性能上的改进
    • 头部压缩
    • 二进制格式
    • 数据流 客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数
    • 多路复用
      • 一个连接中并发多个请求或回应,而不用按照顺序一一对应
      • 降低了延迟,大幅度提高了连接的利用率
    • 服务器推送
  • HTTP/2 有哪些缺陷?HTTP/3 做了哪些优化?
    • 队头阻塞
    • 把 HTTP 下层的 TCP 协议改成了 UDP
    • 头部压缩算法也升级成了 QPack
    • QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互合并成了 3 次,减少了交互次数。

3. HTTP、HTTPS区别

  1. HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输
  2. HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
  3. HTTP 的端口号是 80,HTTPS 的端口号是 443。
  4. HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

4. SSL握手过程

  1. ClientHello

    首先,由客户端向服务器发起加密通信请求,也就是 ClientHello 请求。在这一步,客户端主要向服务器发送以下信息:

    1. 客户端支持的 SSL/TLS 协议版本,如 TLS 1.2 版本。
    2. 客户端生产的随机数( Client Random ),后面用于生产「会话秘钥」。
    3. 客户端支持的密码套件列表,如 RSA 加密算法。
  2. SeverHello

    服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello 。服务器回应的内容有如下内容:

    1. 确认 SSL/ TLS 协议版本,如果浏览器不支持,则关闭加密通信。
    2. 服务器生产的随机数( Server Random ),后面用于生产「会话秘钥」。
    3. 确认的密码套件列表,如 RSA 加密算法。
    4. 服务器的数字证书。
  3. 客户端回应

    客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:

    1. 一个随机数( pre-master key )。该随机数会被服务器公钥加密。
    2. 加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
    3. 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。

    上面第一项的随机数是整个握手阶段的第三个随机数,这样服务器和客户端就同时有三个随机数,接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。

  4. 服务器的最后回应

    服务器收到客户端的第三个随机数( pre-master key )之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发生最后的信息:

    1. 加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
    2. 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。

    至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。

5. IP地址分类、缺点、改进

  • 分类

    私有范围
    A0.0.0.0-127.255.255.25510.0.0.0-10.255.255.255
    B128.0.0.0-191.255.255.255172.16.0.0-172.31.255.255
    C192.0.0.0-223.255.255.25592.168.0.0-192.168.255.255
    D224.0.0.0-239.255.255.255
    E240.0.0.0-255.255.255.255
  • 缺点

    1. 同一网络下没有地址层次,缺少地址的灵活性
    2. 不能很好的与现实网络匹配
  • 改进

    • 无分类地址 CIDR
    • 子网划分

6. IPv6与v4首部差异

  • 取消了首部校验和字段。 因为在数据链路层和传输层都会校验,因此 IPv6 直接取消了 IP 的校验。
  • 取消了分片/重新组装相关字段。 分片与重组是耗时的过程,IPv6 不允许在中间路由器进行分片与重组,这种操作只能在源与目标主机,这将大大提高了路由器转发的速度。
  • 取消选项字段。 选项字段不再是标准 IP 首部的一部分了,但它并没有消失,而是可能出现在IPv6 首部中的「下一个首部」指出的位置上。删除该选项字段使的 IPv6 的首部成为固定长度的40 字节

7. ARP、DHCP、DNS、IGMP过程

  • ARP —— 通过 ARP 协议,求得下一跳的 MAC 地址
    • 主机会通过广播发送 ARP 请求,这个包中包含了想要知道的 MAC 地址的主机 IP 地址。
    • 当同个链路中的所有设备收到 ARP 请求时,会去拆开 ARP 请求包里的内容,如果 ARP 请求包中的目标 IP 地址与自己的 IP 地址一致,那么这个设备就将自己的 MAC 地址塞入 ARP 响应包返回给主机。
  • DHCP —— 动态获取 IP 地址
    • 客户端首先发起 DHCP 发现报文(DHCP DISCOVER) 的 IP 数据报,由于客户端没有 IP 地址,也不知道DHCP 服务器的地址,所以使用的是 UDP 广播通信,其使用的广播目的地址是255.255.255.255(端口 67) 并且使用 0.0.0.0(端口 68) 作为源 IP 地址。DHCP 客户端将该IP 数据报传递给链路层,链路层然后将帧广播到所有的网络中设备。
    • DHCP 服务器收到 DHCP 发现报文时,用 DHCP 提供报文(DHCP OFFER) 向客户端做出响应。该报文仍然使用 IP 广播地址 255.255.255.255,该报文信息携带服务器提供可租约的 IP 地址、子网掩码、默认网关、DNS 服务器以及 IP 地址租用期。
    • 客户端收到一个或多个服务器的 DHCP 提供报文后,从中选择一个服务器,并向选中的服务器发送 DHCP 请求报文(DHCP REQUEST进行响应,回显配置的参数。
    • 最后,服务端用 DHCP ACK 报文对 DHCP 请求报文进行响应,应答所要求的参数。
  • DNS
    1. 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址)。
    2. 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
    3. 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归.com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
    4. 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP地址吗?”
    5. 顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
    6. 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
    7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
    8. 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接
  • IGMP
    • 查询机制
      • 路由器会周期性发送目的地址为 224.0.0.1 (表示同一网段内所有主机和路由器) IGMP 常规查询报文
      • 主机1 和 主机 3 收到这个查询,随后会启动「报告延迟计时器」,计时器的时间是随机的,通常是 0~10 秒,计时器超时后主机就会发送 IGMP 成员关系报告报文(源 IP 地址为自己主机的 IP地址,目的 IP 地址为组播地址)。如果在定时器超时之前,收到同一个组内的其他主机发送的成员关系报告报文,则自己不再发送,这样可以减少网络中多余的 IGMP 报文数量。
      • 路由器收到主机的成员关系报文后,就会在 IGMP 路由表中加入该组播组,后续网络中一旦该组播地址的数据到达路由器,它会把数据包转发出去。
    • 离开机制
    • 情况1
      • 主机 1 要离开组 224.1.1.1,发送 IGMPv2 离组报文,报文的目的地址是 224.0.0.2(表示发向网段内的所有路由器)
      • 路由器 收到该报文后,以 1 秒为间隔连续发送 IGMP 特定组查询报文(共计发送 2 个),以便确认该网络是否还有 224.1.1.1 组的其他成员。
      • 主机 3 仍然是组 224.1.1.1 的成员,因此它立即响应这个特定组查询。路由器知道该网络中仍然存在该组播组的成员,于是继续向该网络转发 224.1.1.1 的组播数据包
    • 情况2
      • 主机 1 要离开组播组 224.1.1.1,发送 IGMP 离组报文。
      • 路由器收到该报文后,以 1 秒为间隔连续发送 IGMP 特定组查询报文(共计发送 2 个)。此时在该网段内,组 224.1.1.1 已经没有其他成员了,因此没有主机响应这个查询。
      • 一定时间后,路由器认为该网段中已经没有 224.1.1.1 组播组成员了,将不会再向这个网段转发该组播地址的数据包

8. ICMP

确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。

  • ICMP 包头的类型字段,大致可以分为两大类:
    • 用于诊断的查询消息,「查询报文类型」
      • 8 回送请求
      • 0 回送应答
    • 通知出错原因的错误消息,「差错报文类型」
      • 3 目标不可达
        • 0 网络
        • 1 主机
        • 2 协议
        • 3 端口
        • 4 需要分片但设置了不分片
      • 4 原点抑制
        • 增大 IP 包的传输间隔,减少网络拥堵的情况
      • 5 重定向
      • 11 超时
        • TTL ( Time To Live ,生存周期),它的值随着每经过一次路由器就会减1,直到减到 0 时该 IP 包会被丢弃。
  • 应用
    • 追踪去往目的地时沿途经过的路由器
    • 确定路径的 MTU

9. 键入网址后会发生什么

  1. HTTP

    • 【1】URL 进行解析,从而生成发送给 Web 服务器的请求信息
    • 【2】生产 HTTP 请求信息
  2. DNS

    • 【3】查询服务器域名对应的 IP 地址
  3. 协议栈

  4. TCP

    • 包头格式

      • 源端口号和目标端口号是不可少的,如果没有这两个端口号,数据就不知道应该发给哪个应用。
      • 序号。这个是为了解决包乱序的问题。
      • 确认号。目的是确认发出去对方是否有收到。如果没有收到就应该重新发送,直到送达,这个是为了解决丢包的问题。
      • 状态位。例如 SYN 是发起一个连接, ACK 是回复, RST 是重新连接, FIN 是结束连接等。TCP 是面向连接的,因而双方要维护连接的状态,这些带状态位的包的发送,会引起双方的状态变更。
      • 窗口大小。TCP 要做流量控制,通信双方各声明一个窗口(缓存大小),标识自己当前能够的处理能力。
      • 拥塞控制。对于真正的通路堵车不堵车,它无能为力,唯一能做的就是控制自己,也即控制发送的速度。不能改变世界,就改变自己嘛。
    • 【4】三次握手

      1. 一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN状态。
      2. 然后客户端主动发起连接 SYN ,之后处于 SYN-SENT 状态。
      3. 服务端收到发起的连接,返回 SYN ,并且 ACK 客户端的 SYN ,之后处于 SYN-RCVD 状态。
      4. 客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK ,之后处于ESTABLISHED 状态,因为它一发一收成功了。
      5. 服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态。

      三次握手目的是保证双方都有发送和接收的能力

    • MTU :一个网络包的最大长度,以太网中一般为 1500 字节。
      MSS :除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度

    • 【5】TCP 报文生成

  5. IP

    • 源地址 IP 和 目标地址 IP
      • 源地址IP,即是客户端输出的 IP 地址;
      • 目标地址,即通过 DNS 域名解析得到的 Web 服务器 IP
    • 【6】多网卡路由选择
      • 路由表规则 ,子网掩码( Genmask )进行与运算
    • 【7】IP报文生成
  6. MAC

    • 在 MAC 包头里需要发送方 MAC 地址和接收方目标 MAC 地址,用于两点之间的传输。
    • 一般在 TCP/IP 通信里,MAC 包头的协议类型只使用:
      • 0800 : IP 协议
      • 0806 : ARP 协议
    • 【8】ARP协议查找路由器MAC地址
    • 【9】MAC报文生成
  7. 网卡

    • 【10】网卡驱动从 IP 模块获取到包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列
    • 【11】网卡会将包转为电信号,通过网线发送出去
  8. 交换机 —— 二层网络设备 没有MAC地址

    • 【12】将电信号转换为数字信号,通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区
    • 【13】根据 MAC 地址表查找 MAC 地址,然后将信号发送到相应的端口
      • 地址表中找不到指定的 MAC 地址。这可能是因为具有该地址的设备还没有向交换机发送过包,或者这个设备一段时间没有工作导致地址被从地址表中删除了。
      • 这种情况下,交换机无法判断应该把包转发到哪个端口,只能将包转发到除了源端口之外的所有端口上,无论该设备连接在哪个端口上都能收到这个包。
      • 这样做不会产生什么问题,因为以太网的设计本来就是将包发送到整个网络的,然后只有相应的接收者才接收包,而其他设备则会忽略这个包。
  9. 路由器 —— 三层网络设备

    • 【14】电信号到达网线接口部分,路由器中的模块会将电信号转成数字信号,然后通过包末尾的 FCS进行错误校验。
    • 【15】如果没问题则检查 MAC 头部中的接收方 MAC 地址,看看是不是发给自己的包,如果是就放到接收缓冲区中,否则就丢弃这个包。
    • 查询路由表确定输出端口
    • 发送
      • 根据路由表的网关列判断对方的地址。如果网关是一个 IP 地址,则这个IP 地址就是我们要转发到的目标地址,还未抵达终点,还需继续需要路由器转发。如果网关为空,则 IP 头部中的接收方 IP 地址就是要转发到的目标地址,也是就终于找到 IP 包头里的目标地址了,说明已抵达终点

10. TCP包头格式、定义、三次握手、为什么不是两次四次

  • 包头格式
    • 序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
    • 确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
    • 控制位:
      • ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN包之外该位必须设置为 1 。
      • RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
      • SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
      • FIN:该位为 1 时,表示今后不会再有数据发送,希望断开
  • 定义
    • TCP 是面向连接的、可靠的、基于字节流的传输层通信协议
    • TCP连接:用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket、序列号和窗口大小称为连接。
  • 三次握手
    • 一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN状态
    • 客户端会随机初始化序号( client_isn ),将此序号置于 TCP 首部的「序号」字段中,同时把SYN 标志位置为 1 ,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。
    • 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号( server_isn ),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn +1 , 接着把 SYN 和 ACK 标志位置为 1 。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态
    • 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。
    • 服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态
  • 为什么不是两次四次
    • 三次握手才可以阻止重复历史连接的初始化(主要原因)
    • 三次握手才可以同步双方的初始序列号
    • 三次握手才可以避免资源浪费
  • 性能提升
    • 调整SYN报文的重传次数 /proc/sys/net/ipv4/tcp_syn_retries
    • 调整SYNACK报文的重传次数 /proc/sys/net/ipv4/tcp_synack_retries
    • 绕过三次握手 net.ipv4.tcp_fastopen
    • 调整SYN半连接队列长度 tcp_max_syn_backlog、somaxconn、backlog
      • 当 max_syn_backlog > min(somaxconn, backlog) 时, 半连接队列最大值 max_qlen_log = min(somaxconn, backlog) * 2;
      • 当 max_syn_backlog < min(somaxconn, backlog) 时, 半连接队列最大值 max_qlen_log = max_syn_backlog * 2;
      • 如果「当前半连接队列」没超过「理论半连接队列最大值」,但是超过 max_syn_backlog -(max_syn_backlog >> 2),那么处于 SYN_RECV 状态的最大个数就是 max_syn_backlog – (max_syn_backlog >> 2);
      • 如果「当前半连接队列」超过「理论半连接队列最大值」,那么处于 SYN_RECV 状态的最大个数就是「理论半连接队列最大值」;
    • 调整accpet队列长度 min(backlog,somaxconn)

11. TCP、UDP区别、应用场景

  • 区别
    1. 连接
      • TCP 是面向连接的传输层协议,传输数据前先要建立连接。
      • UDP 是不需要连接,即刻传输数据。
    2. 服务对象
      • TCP 是一对一的两点服务,即一条连接只有两个端点。
      • UDP 支持一对一、一对多、多对多的交互通信
    3. 可靠性
      • TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达。
      • UDP 是尽最大努力交付,不保证可靠交付数据。
    4. 拥塞控制、流量控制
      • TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
      • UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
    5. 首部开销
      • TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。
      • UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
    6. 传输方式
      • TCP 是流式传输,没有边界,但保证顺序和可靠。
      • UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
    7. 分片不同
      • TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
      • UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层,但是如果中途丢了一个分片,则就需要重传所有的数据包,这样传输效率非常差,所以通常 UDP 的报文应该小于 MTU
  • 应用场景:
    • 由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:FTP 文件传输、HTTP / HTTPS
    • 由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:包总量较少的通信,如 DNS 、 SNMP 等 视频、音频等多媒体通信、广播通信

12. SYN攻击如何避免

  • 增大半连接队列min(somaxconn, backlog);
    • net.ipv4.tcp_max_syn_backlog
    • core.somaxconn
  • 开启 tcp_syncookies 功能
    • net.ipv4.tcp_syncookies = 1
      • 0 值,表示关闭该功能;
      • 1 值,表示仅当 SYN 半连接队列放不下时,再启用它;
      • 2 值,表示无条件开启功能;
  • 减少 SYN+ACK 重传次数
    • net.ipv4.tc_synack_retries
  • net.core.netdev_max_backlog
  • net.ipv4.tcp_abort_on_overflow

13. TCP四次挥手、TIME_WAIT作用、保活机制 132

  • 四次挥手
    1. 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN报文,之后客户端进入 FIN_WAIT_1 状态。
    2. 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。
    3. 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
    4. 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
    5. 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
    6. 服务器收到了 ACK 应答报文后,就进入了 CLOSED 状态,至此服务端已经完成连接的关闭。
    7. 客户端在经过 2MSL 一段时间后,自动进入 CLOSED 状态,至此客户端也完成连接的关闭。
  • 性能优化
    • 调整FIN报文重传次数 Tcp_orphan_retries
    • 调整FIN_WAIT2状态的时间(close函数) Tcp_fin_timeout
    • 调整孤儿连接的上限个数 tcp_max_orphan
    • 调整time_wait状态的上限个数 tcp_max_tw_buckets
    • 复用time_wait状态的连接(客户端) tcp_tw_reuse、tcp_timestamps
  • TIME_WAIT作用
    • 防止具有相同「四元组」的「旧」数据包被收到。过 2MSL 这个时间,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。
    • 保证「被动关闭连接」的一方能被正确的关闭,即保证最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。
  • TIME_WAIT过多的危害
    • 第一是服务器内存资源占用;
    • 第二是对客户端端口资源的占用,一个 TCP 连接至少消耗一个本地端口;
  • 如何优化 TIME_WAIT
    • net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项;
    • net.ipv4.tcp_max_tw_buckets。接一旦超过这个值时,系统就会将所有的TIME_WAIT 连接状态重置。
  • 保活机制
    • net.ipv4.tcp_keepalive_time=7200
    • net.ipv4.tcp_keepalive_intvl=75
    • net.ipv4.tcp_keepalive_probes=9

14. 重传机制

  • 超时重传
    • RTT 就是数据从网络一端传送到另一端所需的时间,也就是包的往返时间。
    • 超时重传时间是以 RTO (Retransmission Timeout 超时重传时间)表示
    • 超时重传时间 RTO 的值应该略大于报文往返 RTT 的值
  • 快速重传
    • 快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传
    • 快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
  • SACK
    • Selective Acknowledgment 选择性确认
    • 可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据
    • net.ipv4.tcp_sack打开
  • D-SACK
    • 可以让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了;
    • 可以知道是不是「发送方」的数据包被网络延迟了;
    • 可以知道网络中是不是把「发送方」的数据包给复制了;
    • net.ipv4.tcp_dsack打开

15. 滑动窗口

  • 发送窗口三个指针
    • SND.WND :表示发送窗口的大小(大小是由接收方指定的);
    • SND.UNA :是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是#2 的第一个字节。
    • SND.NXT :也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3的第一个字节。
    • 指向 #4 的第一个字节是个相对指针,它需要 SND.UNA 指针加上 SND.WND 大小的偏移量,
      就可以指向 #4 的第一个字节了
  • 接收窗口两个指针
    • RCV.WND :表示接收窗口的大小,它会通告给发送方。
    • RCV.NXT :是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号,也就是 #3 的第一个字节。
    • 指向 #4 的第一个字节是个相对指针,它需要 RCV.NXT 指针加上 RCV.WND 大小的偏移量,就可以指向 #4 的第一个字节了
  • 数据传输调优
    • 扩大窗口大小 tcp_window_scaling
    • 调整发送缓冲区范围 tcp_wmem
      • 第一个数值是动态范围的最小值,4096 byte = 4K;
      • 第二个数值是初始默认值,87380 byte ≈ 86K;
      • 第三个数值是动态范围的最大值,4194304 byte = 4096K(4M)
    • 调整接收缓冲区范围 tcp_rmem、tcp_moderate_rcvbuf
      • 第一个数值是动态范围的最小值,表示即使在内存压力下也可以保证的最小接收缓冲区大小,4096 byte = 4K;
      • 第二个数值是初始默认值,87380 byte ≈ 86K;
      • 第三个数值是动态范围的最大值,6291456 byte = 6144K(6M);
    • 调整内存范围 tcp_mem
      • 上面三个数字单位不是字节,而是「页面大小」,1 页表示 4KB,它们分别表示:
        • 当 TCP 内存小于第 1 个值时,不需要进行自动调节;
        • 在第 1 和第 2 个值之间时,内核开始调节接收缓冲区的大小;
        • 大于第 3 个值时,内核不再为 TCP 分配新内存,此时新连接是无法建立的;

16. 流量控制

  • 让「发送方」根据「接收方」的实际接收能力控制发送的数据量,避免「发送方」的数据填满「接收方」的缓存
  • TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间再减少缓存,这样就可以避免了丢包情况。
  • 窗口关闭:如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。
  • 窗口探测 ( Window probe ) 报文:窗口探测的次数一般为 3 次,每次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。
  • 如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。
  • 发送方延迟发送
    • 使用 Nagle 算法,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据:
      • 没有已发送未确认报文时,立刻发送数据
      • 要等到窗口大小 >= MSS 或是数据大小 >= MSS
      • 收到之前发送数据的 ack 回包
    • TCP_NODELAY关闭
  • 接收方延迟确认
    • 当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方
    • 当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送
    • 如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK

17. 拥塞控制

  • 避免「发送方」的数据填满整个网络
  • 慢启动
    • 指数性的增长
    • 慢启动门限 ssthresh(slow start threshold)
  • 拥塞避免
    • 线性增长
  • 拥塞发生
  • 快速恢复
    • 超时重传
      • ssthresh 设为 cwnd/2 ,
      • cwnd 重置为 1
    • 快速重传
      • cwnd = cwnd/2 ,也就是设置为原来的一半;
      • ssthresh = cwnd ;
      • 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);
      • 重传丢失的数据包;
      • 如果再收到重复的 ACK,那么 cwnd 增加 1;
      • 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;
  • TCP_QUICKACK

18. 网络模型

  • OSI模型
    • 应用层,负责给应用程序提供统一的接口;
    • 表示层,负责把数据转换成兼容另一个系统能识别的格式;
    • 会话层,负责建立、管理和终止表示层实体之间的通信会话;
    • 传输层,负责端到端的数据传输;
    • 网络层,负责数据的路由、转发、分片;
    • 数据链路层,负责数据的封帧和差错检测,以及 MAC 寻址;
    • 物理层,负责在物理网络中传输数据帧;
  • TCP/IP模型
    • 应用层,负责向用户提供一组应用程序,比如 HTTP、DNS、FTP 等;
    • 传输层,负责端到端的通信,比如 TCP、UDP 等;
    • 网络层,负责网络包的封装、分片、路由、转发,比如 IP、ICMP 等;
    • 网络接口层,负责网络包在物理网络中的传输,比如网络包的封帧、 MAC 寻址、差错检测,以及通过网卡传输网络帧等;