[面试] 计算机网络

132 阅读20分钟

03 计算机网络

网络分层模型

1. OSI 分层模型

img
# 应用层
  - 数据单位: 报文
  - 协议: http, DNS
  - 为应用程序提供网络数据传输服务;
# 表示层
  - 数据压缩, 加密, 解密, 字符集格式转换
# 会话层
  - 建立和管理会话
# 运输层
  - 数据单位: 数据报
  - 协议: TCP, UDP
  - 为进程提供网络数据传输服务;
  - TCP: 面向连接, 可靠的数据传输服务, 比较慢;
  - UDP: 无连接, 不可靠的数据传输服务, 及时性高;
# 网络层
  - 数据单位: IP 数据报
  - 协议: APR, ICMP, 路由选择协议(RIP, OSPF)
  - 为整个网络中的主机提供数据传输服务;
# 链路层
  - 数据单位: 帧
  - 为同一个子网中的主机提供数据传输服务, 交换机通过 MAC 地址实现;
# 物理层
  - 数据单位: 比特流
  - 数据在物理缆线上的传输;

2. 网络地址划分

# 三类地址
  - A类: 8 位网络号 + 24位主机号 掩码 -255.0.0.0
  - B类: 16位网络号 + 16位主机号 掩码 -255.255.0.0
  - C类: 24位网络号 + 8 位主机号 掩码 -255.255.255.0
# 子网划分
  - 网络分类是为了方便子网划分, 不同类型的网络给子网划分提供不同的规模上限, A类地址的子网可以容纳最多 2^24-2 个主机, B类 2^16-2, C类 2^8-2;
  - 子网划分将 32 位 IP 分为三个部分: 网络号 + 子网号 + 主机号 (网络号位数固定的, 子网号通过占用原来的主机号来缩小子网规模)
  - 子网掩码: 32 位的二进制数, 将网络号和子网号置为 1, 主机号置为 0, 获得子网掩码, 掩码和ip与操作活动子网网络号;
  - 广播地址: 主机号均为 1
  - 本地地址: 主机号均为 0 
  - 网关地址: 主机号为 1 (或广播地址 -1)
# 常用子网地址
  - 10.0.0.0 ~ 10.255.255.255 (24)
  - 172.16.0.0.0 ~ 172.31.0.0 (20)
  - 192.168.0.0 ~ 192.168.0.0 (16)

3. 网络层 IP 数据报格式

# IP 数据报
  - 由路由器解析, 用于数据包在整个网络主机间的路由与转发;
# IP 数据报首部主要内容
  - 版本: IPV4 或 IPV6;
  - 生存时间: TTL, 以路由器跳数为单位;
  - 分片: 通过标识符和偏移量, 指示同一数据包分片后的内容顺序(大的数据包分片后, 标识符不变, 偏移量依次增加);
  - 首部检验和: 验证数据完整性, (发送方计算首部数据1的补码和, 然后取反放入检验区, 接收方联同检验区数据一同计算1的补码和, 相当于原码加反码, 获得16位1)
  - 目标地址: 数据包发送的目标主机 IP;
  - 源地址: 发送主机的 IP;

4. 网络层协议

# 地址解析协议 ARP
  - 通过在局域网中广播目标主机 IP, 获得目标主机的 MAC 地址;
# ICMP
  - 实现 ping 和 Traceroute 操作;
  - 路由追踪(Traceroute): 发送者依次发送 TTL 值为 1,2,3... 的数据包, 然后让路劲上的每个路由器返回错误报告, 获得路劲 IP 和往返时间;
# 路由选择协议
  - 当数据包要发送到外部网络时, 需要路由器查询路由表, 将数据包转发至匹配的同级(子网)路由器或者上级(默认)路由器;
  - RIP: 相邻路由器周期性交换路由表信息来更新和维护路由表, 有 15 跳限制, 速度较慢;
  - OSPF: 链路状态协议, 当路由器检测到链路状态改变时, 主动在网络中广播链路变化的信息, 速度快, 没有跳数限制;

5. 传输层协议 (UDP 和 TCP)

# 特点
  - TCP: 面向连接, 可靠的数据传输服务, 比较慢; 仅支持一对一通信;
  - UDP: 无连接, 不可靠的数据传输服务, 及时性高; 支持一对一, 一对多, 多对一的通信;
# UDP 首部
  - 包括源端口, 目的端口, 长度, 检验和(包括部分IP首部);
# TCP 首部
  - 源端口/目的端口;
  - 序号/确认号;
  - 数据偏移: TCP 首部长度是可变的, 因此需要数据偏移量来指示数据开始位置与数据报起始位置的差距;
  - 标志位: ACK, SYN, FIN, RST;
  - 窗口: 发送者的窗口限制, 受内部缓冲区大小的限制;

6. 应用层协议

# DNS
  - 端口: 53
  - 基于: UDP/TCP (长度超过 512 字节时使用 TCP)
  - DNS 是一个分布式数据库, 提供了域名和 IP 地址之间的转换;

# FTP
  - 端口: 20(数据连接),21(控制连接)
  - 基于: UDP/TCP (长度超过 512 字节时使用 TCP)
  - FTP 在传输文件时需要建立两个链接:
    - 控制连接: 客户端发送指令给服务端;
    - 数据连接: 服务端传输文件给客户端;
      - 主动模式: 服务端主动连接到客户端, 发起文件传输; 服务端指定端口为 20, 客户端随机端口应答;
      - 被动模式: 客户端主动连接到服务端, 发起文件传输请求; 客户端指定随机端口, 服务端随机端口应答;
      - 区别: 主动模式下, 客户端需要开放所有端口, 需要客户端配置防火墙; 被动模式下, 服务端需要开发所有端口, 导致服务端安全性减弱;

# SSH
  - 端口: 22
  - 基于: TCP
  - 用于远程登录主机(UNIX), 提供安全, 加密的通信;
  - 口令登录: 根据 ip 连接到服务器, 服务器返回服务器公钥, 接收则要求输入登录密码并以公钥加密后发送给服务器, 服务器接受后用私钥解密, 验证成功后完成登录;
  - 口令登录的问题: 每次登录需要输入密码进行验证; 无法保障服务器的身份; 登录密码在网络上传播, 诺服务器是伪造的, 那么对方可以获取登录密码;
  - 公钥登录:  1) 需要生成一对公/私钥对, 然后公钥放在服务端, 私钥放在远程登录端; 
             2) 当客户端连接到服务器时, 服务器用公钥加密一段随机字符, 然后发送给客户端;
             3) 客户端用私钥解密, 获得随机字符, 然后再用私钥加密, 再发送给服务端;
             4) 服务端用公钥解密, 如果随机字符和原来的匹配, 则登录成功;
  - 公钥登录问题: 公钥登录虽然避免了登录密码在网络上的传输, 但是初始化配置时, 必须同时访问远程服务器和客户端主机, 往往需要先用口令登录的方式先登录远程服务器

# DHCP
  - 端口: 67/68
  - 基于: UDP
  - 为新登陆到网络上的主机自动分配动态的 IP, 包括 IP 地址, 子网掩码, 网关IP;
  - 过程: 1) 主机发送 Discover 报文, 以广播的方式在子网中发送, 其目标端口为 67, 源端口为 68;
         2) DHCP 服务器接收到报文后, 返回给客户端IP请求的预分配结果; 可能有多个服务器接收并返回, 但客户端一般只取最早返回的那个;
           (DHCP 服务器维护 静态IP 和 动态IP 两张表, 它们保存了主机 MAC 地址和分配的 IP 地址间的映射关系, 前者保持不变, 后者动态更新;
            静态请求: 客户端发送请求时, 可以指定静态 IP, 诺 DHCP 在静态IP表中匹配到它的 MAC 地址, 则返回指定的 IP, 静态请求成功;
            动态请求: 诺客户端指定的 IP 匹配不成功, 则在动态表中查询, 诺该 IP 未分配, 则返回指定的 IP, 静态请求成功; 否则失败;)
         3) 客户端接收到返回的预分配 IP 后, 向服务端返回正式的 IP 申请;
         4) 服务器返回确认包, 最终完成动态 IP 的分配;
         (租约: 为了及时回收 IP 资源, DHCP 服务器对分配出去的 IP 都规定了租期, 诺在租约期限内没有再次发送 IP 申请, 将自动回收 IP 资源;
               客户端一般在租期到期前重新发送的 IP 请求, 且请求会经过静态/动态租约表的匹配, 所以一直在线的主机将维持原有 IP 不变, 相当于续约;)

# 邮箱
  邮件发送协议: SMTP
  邮件读取协议: POP3, IMAP
  邮件发送过程: 1) 发件人通过 SMTP 将邮件发送到发送方邮件服务器;
              2) 发送方邮件服务器通过 SMTP 将邮件发送到接收方邮件服务器;
              3) 接收方邮件服务器通过 POP3 或 IMAP 将邮件读取到接受者;
  [SMTP]
  - 端口: 25
  - 基于: TCP
  - SMTP 只能发送 ASCII 码, 因此需要通过 MIME 将用户邮件翻译后发送, 读取时同样需要 MIME 作转译;
  
  [POP3]
  - 端口: 110
  - 基于: TCP 
  - POP3 用于读取接收方邮件服务器上的邮件, 但是读取后服务器上的邮件默认会被删除(新版本也可以不删除);
  
  [IMAP]
  - 端口: 143
  - 基于: TCP  
  - IMAP 保持客户端和服务器上的邮件内容同步, 如果不手动删除邮件, 服务器上邮件一直存在;

7. Web 页面请求过程

# 涉及的协议
  - DNS, HTTP, TCP, IP(ARP);
# 过程
  - DNS
    * 浏览器输入网址 URL, 然后被发送到 DNS 服务器;
    * DNS 服务器返回网址所在服务器的 IP 地址;
  - HTTP
    * 浏览器生成请求 Web 页面的 HTTP 报文;
  - TCP
    * TCP 协议将 HTTP 报文分割成多个报文段, 并进行排序;
    * 设定目标端口, 通过3次握手, 与接收者建立可靠的 socket 连接;
  - IP
    * 根据目标 IP 地址, 利用 ARP 协议获得下一跳 MAC 地址;
    * 通过中间路由器, 不断的路由选择和转发, 将数据包转发到拥有目标 IP 的接收方主机;
  - TCP
    * 接收方 TCP 协议重组 HTTP 数据报, 并将其传入指定接口的进程中;
  - HTTP
    * 接收方根据 HTTP 协议解析数据报, 然后返回请求的 Web 页面数据;
    * 返回的 Web 页面也将通过相同的方式到达请求者并在浏览器上解析出 web 页面;

TCP

1. TCP 连接过程和断开过程

img

# 三次握手 - 建立连接
  - 客户端发送带有 `SYN` 标志位的数据包给服务端, 序列号为 `x` ,请求建立连接;
  - 服务端接收到客户端发送的 `SYN` 包后, 也同样返回序列号为`y` 的 `SYN` 数据包给客户端, 并且将其中的 `ACK` 标志位置为`x+1` , 表示确认连接请求;
  - 客户端接收到服务端 `SYN` 数据包后, 返回 `ACK` 标志位置为 `y+1` 的数据包进行确认, 从而完成连接的建立;
# 可靠数据传输
  - 连接建立后, 客户端可以发送包含数据或请求的数据包给服务端, 其中 `ACK` 标准位都置为上一次服务端发送数据包的序列号加一;
  - 服务端接收到客户端数据或请求后, 返回相应的数据包, 其中 `ACK` 标准位都置为接收到的客户端数据包序列号加一;
  - 在这里, 通信过程中发送数据包的 `ACK` 标准位都在接收数据包序列的基础上加一, 起到了确认对方数据包已被接受的作用. 如果任何一方没有收到带有正确 `ACK` 标准位的数据包, 即表示传输过程有数据包丢失, 需要从数据包丢失位置重传;
# 四次挥手 - 断开连接
  - 客户端发送带有 `FIN` 标志位的数据包给服务端, 请求断开连接;
  - 服务端接受到数据包后, 诺还有未发送完毕的数据, 则返回仅带有 `ACK` 标志位的确认数据包, 然后在完成数据发送后, 再返回 `FIN` 数据包; 
  - 诺没有未发送完毕的数据, 则可以把上述两个数据包合在一起, 一次发送完成;
  - 客户端接收到服务端 `FIN` 数据包后, 返回 `ACK` 确认数据包, 然后等待 2 个 `MSL` 最大段生命周期后, 诺没有数据返回, 则证明了服务端已经接收到确认数据包, 完成连接的断开; 诺在等待过程中收到服务端重传的 `FIN` 数据包,则证明发送的 `ACK` 数据包被丢失, 客户端需要重新返回 `ACK` 数据包;

2. TCP 可靠性

# 序列号 + 确认应答 + 超时重传
  - 客户端和服务端双方发送数据包, 都要带上序列号, 数据包的序列号依次递增, 保证了数据包内容的先后顺序;
  - 当对方接受到数据包后, 都需要返回一个 `ACK` 确认包, 其值为接受到的数据包序列号 +1, 保证了发送者收到确认, 可以继续后续内容的发送;
  - 诺发生数据包丢失, 发送者可能接受不到确认包, 此时发送这等待一段时间后重发数据包;
  - 超时时间计算: 平均往返时间 ((1-a)*ave_RTT + a*cur_RTT) + 额外等待时间;
# 窗口控制
  - TCP 利用窗口控制来提高传输速度, 即通信双方发送数据包, 不必一个一个的发送, 然后一个一个的等待对方的确认, 而是一次性可以发送多个;
  - 比如将窗口控制在100, 发送端可以一次性连续发送100个数据包, 然后等待对方应答;
  - 接受者会及时地返回当前接收到的连续数据包中最大的序号, 当接收者连续三次返回相同的序号时, 表示在该位置发生了数据包丢失, 发送者需要重传;
  - 窗口包括了发送者的发送窗口和接收者的接收窗口, (不考虑网络因素), 它们的大小分别和发送缓冲区和接收缓冲区有关, 当两者不一致时, 取小的那个值为准;
  - 网络稳定时, 窗口的大小是固定的, 但是窗口两端的序列号是动态变化的;
    - 如发送段初始时窗口两端是 1 和 100, 在发送途中接收到 50 的确认包, 那么窗口两端会动态更新为 50 和 150;
# 拥塞控制
  - 当网络上有大量数据进行通信时, 会造成网络拥塞, 大量的数据包会丢失, 此时重传机制并不能解决数据包丢失问题;
  - 所有引入了拥塞控制, 其原理是通过动态地调整窗口的大小, 来限制网络中发送的数据包数量;
  - 拥塞控制分为: 慢启动, 拥塞避免, 快重传, 快恢复
    [超时] - 网络拥塞
      - 慢启动: 窗口值降为 1, 然后在能收到确认返回的情况下, 以 *2 的方式加倍增长, 直至预设的阈值;
      - 拥塞避免: 窗口值达到预设阈值后, 在能收到确认返回的情况下, 以 +1 的方式线性增长, 直至最大的窗口值(受两端缓冲区大小限制);
    [丢失(连续接收到3个重复确认)] - 个别丢失, 非拥塞
      - 快重传: 立即重传重复确认的数据包;
      - 快恢复: 将阈值和窗口值都降为 当前窗口值/2, 然后进入拥塞避免阶段;

3. 半连接和全连接

img

# 三次握手阶段
  - 服务器接收到客户端 `SYN` 数据包后, 先将其先放入 `SYN` 队列 (半连接队列);
  - 服务端发送带有 `SYN` 和`ACK` 标志位的确认数据包后, 诺接收客户端的返回, 则将该连接从 `SYN` 队列中取出, 放入 `ACCEPT` 队列 (全连接队列);
  - 服务端的应用程序只会调用 `ACCEPT` 队列中的套接字, 不会调用 `SYN` 队列套接字; 

# 队列满时的情况
  - 直接丢弃, 客户端等待一段时间后重发;
  - 返回 Reset, 客户端重新开始握手; 

# Recv-Q 和 Send-Q
  - 使用 'ss' 命令查看系统 Socket 状态, 有 Listen 和 非Listen 两种状态;
  - Listen 状态下, 
    * Recv-Q 表示全连接队列中等待被进程 accept() 的连接;
    * Send-Q 表示全连接队列的最大值, 由 min(baklog,somaxconn) 决定;
  - 非 Listen 状态下,
    * Recv-Q 表示接受队列字节数;
    * Send-Q 表示发送队列字节数;

4. TIME_WAIT 过多

# TIME_WAIT 作用
- 主动结束连接方, 在最后一次挥手时发出 ACK 包, 是不需要对方回复的;
- 但这种情况下会存在 ACK 丢失问题, 此时接收方会不断重复发送 FIN 数据包;
- 因此, 主动结束连接方必须保持 TWIM_WAIT 状态一段时间(2 个 `MSL` 最大段生命周期), 确保对方已经接收;

# 问题
- 当服务器作为主动结束连接方, 并且结束大量并发短链接时, 会出现大量套接字处于 TIME_WAIT 状态;
- 新的连接请求发送到服务器, 产生套接字不够用的问题;

# 解决
- 修改内核文件
- net.ipv4.tcp_tw_reuse = 1     开启重用。允许将 TIME-WAIT sockets 重新用于新的TCP连接;
- net.ipv4.tcp_tw_recycle = 1   开启TCP连接中 TIME-WAIT sockets 快速回收。
- net.ipv4.tcp_fin_timeout      修改系默认的 TIMEOUT 时间

HTTP

1. HTTPS

# 区别
  [HTTP]
   - 明文通信, 通话内容容易被窃听;
   - 通信双方无法验明身份, 页面容易被劫持(客户端一般不直接和服务端通信, 需要通过中间代理, 如果代理服务器被入侵, 黑客修改了原本跳转到服务器的地址);
   - 劫持后, 用户信息被假的页面获取, 原本的页面提供商被屏蔽, 无法提供服务;
  [HTTPS]
   - 通信双方通信内容被加密, 通信内容窃听后无法被解密;
   - 在连接建立的过程中, 增加了计算步骤, 导致连接建立速度降低;
   - 连接中断后, 重新建立通信较麻烦, 可以通过额外的会话机制快速恢复;
# HTTPS 建立过程
  - 客户端向服务端发送: 支持的协议, 加密算法 和 两个随机数(用于建立后续对称加密的密钥);
  - 服务端向客户端发送: 确认的协议, 加密算法, 两个随机数 及 数字证书(诺服务器需要验证客户端身份, 需要请求客户端证书);
  - 客户端用 CA 的公钥解开数字证书, 检查网址, 期限等信息, 诺没有问题则信任服务端, 然后提取服公钥, 并产生最后两个随机数, 用公钥加密后发送给服务端;
  - 服务端接收后, 用私钥解密, 获得完整的 6 个随机数;
  - 双方都根据约定的方式生成对称密钥, 以后的通信都使用这个对称密钥加密;
# 会话的恢复
  - 由于 HTTPS 在建立连接阶段需要利用非对称加密的方式生产会话密钥, 这个步骤非常耗时, 故引入会话机制, 实现连接意外中断后可以跳过验证过程, 快速恢复连接;
  - 会话ID:  * 该方法是为每一个连接创建一个会话ID, 将会话密钥和会话ID保存在表中, 连接中断后依然保留;
            * 当意外中断发生时, 客户端重新连接到服务器, 并提供会话 ID, 诺该ID在表中匹配, 则直接用原来的会话密钥进行通信;
            * 不足在于, 会话ID只会保存在单节点上, 诺服务器是分布式的, 客户端的请求可能被调度到不同节点上, 会话ID无法完成匹配;
  - 会话令牌: * 当客户端意外断开发起重连接时, 发送会话令牌, 该令牌包含会话密钥, 并且只有服务器可以解开;
            * 任意服务器接收到会话令牌后, 解密并验证其中的数据, 验证通过后获取会话密钥, 立即恢复连接;

Socket 模型

1. UDP 连接

2. TCP 连接

# 1. 建立套接字
# int socket(int domain, int type, int protocol);
  - 返回值: 成功, 返回套接字描述符; 失败, 返回 -1;
  - int domain: 协议簇
     * AF_UNIX(本机通信)
     * AF_INET(TCP/IP – IPv4)
     * AF_INET6(TCP/IP – IPv6)
  - int type: 类型
     * SOCK_STREAM(TCP流)
     * SOCK_DGRAM(UDP数据报)
     * SOCK_RAW(原始套接字)
  - int protocol: 0

# 2. 绑定ip和端口
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  - 返回值: 成功, 非-1; 失败, -1;
  - int sockfd: 套接字描述符
  - const struct sockaddr *addr: 指针,指向结构体地址(ip+端口)
  - socklen_t addrlen: 结构体地址的长度

# 3. 监听/连接 
# int listen(int sockfd, int backlog);
  - 
  - int backlog: 监听队列的最大连接个数
# int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 

3. Unix 域套接字连接

# 与 TCP 类似
  - 在指定域时, 由 AF_INET 改为 AF_UNIX;
  - 在绑定地址时, 由 IP 改为本机的某个文件;

4. 非阻塞 connect() 和 accept()

# accept()
  阻塞模式
    * 阻塞模式下调用accept()函数,而且没有新连接时,进程会进入睡眠状态。
  非阻塞模式
    * 非阻塞模式下调用accept()函数,而且没有新连接时,将返回EWOULDBLOCK错误。
  非阻塞模式select() + accept() 
# connect()函数
  阻塞模式
    * 客户端调用connect()函数将激发TCP的三路握手过程,但仅在连接建立成功或出错时才返回。返回的错误可能有以下几种情况:
  非阻塞工作模式
    * 调用connect()函数会立刻返回EINPROCESS错误,但TCP通信的三路握手过程正在进行,所以可以使用select函数来检查这个连接是否建立成功。

5. HTTP返回码

HTTP协议的响应报文由状态行、响应头部和响应包体组成,其响应状态码总体描述如下:
1xx:指示信息--表示请求已接收,继续处理。

2xx:成功--表示请求已被成功接收、理解、接受。

3xx:重定向--要完成请求必须进行更进一步的操作。

4xx:客户端错误--请求有语法错误或请求无法实现。

5xx:服务器端错误--服务器未能实现合法的请求。

常见状态代码、状态描述的详细说明如下。

200 OK:客户端请求成功。

206 partial content服务器已经正确处理部分GET请求,实现断点续传或同时分片下载,该请求必须包含Range请求头来指示客户端期望得到的范围

300 multiple choices(可选重定向):被请求的资源有一系列可供选择的反馈信息,由浏览器/用户自行选择其中一个。

301  moved permanently(永久重定向):该资源已被永久移动到新位置,将来任何对该资源的访问都要使用本响应返回的若干个URI之一。

302 move temporarily(临时重定向):请求的资源现在临时从不同的URI中获得,

304:not modified :如果客户端发送一个待条件的GET请求并且该请求以经被允许,而文档内容未被改变,则返回304,该响应不包含包体(即可直接使用缓存)。

403 Forbidden:服务器收到请求,但是拒绝提供服务。

t Found:请求资源不存在,举个例子:输入了错误的URL。