1. 网络

1.1. 扩展阅读

图解 QUIC 连接

1.2. 常见问题

1.2.1. 沾包问题

TCP 协议在底层机制上解决了 UDP 协议的顺序问题和重传问题, 但是相比 UDP 又带来了新的问题, TCP 是流式的, 数据包没有边界, 应用程序使用 TCP 通信就会面临这些问题. 因为 TCP 是流式的, 在接收一个大数据包时, 可能会拆分为多个数据包进行发送, 多次 Send 底层也可能会合并成一次进行发送, 这里会使用下面两个操作来解决:

  1. 分包: Server 收到了多个数据包, 需要拆分数据包
  2. 合包: Server 收到的数据包只是一部分, 需要缓存数据, 合并成完整的包.

那么针对这两种情况, 我们需要一些解决方案:

  1. EOF 结束符协议
  2. 固定包头 + 包体协议 (包长度, json格式, html格式等)

1.2.2. TCP 特性

  1. TCP 提供一个 面向连接, 可靠的 字节流服务
  2. 只支持单对单通信, 不支持多播和广播
  3. TCP 使用校验和, 确认和重传机制来保证可靠传输
  4. TCP 给数据字节进行排序, 并使用积累确认保证数据的顺序不变和不重复
  5. TCP 使用滑动窗口机制实现流量控制, 通过动态改变窗口大小进行阻塞控制

1.2.3. (4) tcp的握手与挥手, 握手能否两次? 能否四次? 挥手为什么是4次? 三次会怎么样? (需要了解状态变化)

  • Sequence Number: 初始值是一个随时间递增的数值, 有自己的算法
    • 为什么不用固定值
      • TCP 连接四元组件: src host/port + dst host/port, 这些连接信息十分容易获取, 如果固定初始值就使得第三方十分容易构造一个在窗口允许范围内的 RST 数据包关闭连接.
      • 端口复用的情况下如果 Sequence Number 固定值开始, 那么可能造成新旧连接的数据包一致, 就会导致服务端无法判断这个数据包到底是什么时候的数据包.
  • ACKnum: 值为 Sequence Number + 数据包大小, 表示这个范围内的数据已经收到, 下次传递数据的时候请使用 ACK 数值作为你的 Sequence Number 传递
  • 重试
    • SYN 重试: 客户端未收到服务器的 ACK 重试
    • SYN + ACK 重试: 服务端未收到客户端的 ack 时发起的重试

三次握手 (创建连接) (Three-way Handshake)

三次握手是指建立一个 TCP 连接时, 客户端和服务端一共要发送3个包

  1. 第一次握手 (SYN=1, seq=x)

    服务端监听某个端口时就会处于 LISTEN 状态. 客户端发送一个 TCP 的 SYN 标志位置1的包, 指明客户端打算连接的服务器的端口, 以及初始化序号 X, 保存在包头的序列号 (Sequence Number) 字段里. 发送完毕后, 客户端进入 SYN_SEND 状态

  2. 第二次握手 (SYN=1, seq=y, ACK=1, ACKnum=x+1)

    服务器发回确认包(ACK)应答.即 SYN 标志位和 ACK 标志位均为1. 服务器端选择自己 ISN 序列号, 放到 Seq 域里, 同时将确认序列 (Acknowledgement Number) 设置为客户端的 ISN+1, 即 x+1. 发送完毕后, 服务器端进入 SYN_RECD 状态

  3. 第三次握手 (ACK=1, ACKnum=y+1)

    客户端再次发送确认包 (ACK), SYN 标志位为0, ACK标志位为1, 并且把服务器发来 ACK 的序列号字段 + 1, 放在确认字段中发送给对方, 并且在数据库放 ISN的+1 发送完毕后, 客户端进入 ESTABLISHED 状态, 当服务器端接收到这个包时, 也进入 ESTABLISHED 状态.

四次挥手 (断开链接) (Four-way handshake)

TCP 的连接的断开需要发送四个包. 服务端和客户端均可以主动发起挥手动作. 在 socket 编程中, 任意一方执行 close() 方法操作即可产生挥手操作.

  1. 第一次挥手 (FIN=1, seq=x)

    假设客户端想要关闭连接, 客户端发送一个 FIN 标志位置为1的的, 表示自己已经没有数据可以发送了, 但是仍可以接收数据.

    发送完毕后, 客户端进入 FIN_WAIT_1 状态.

  2. 第二次挥手 (ACK=1, ACKnum=x+1)

    服务器端确认客户端的 FIN 包, 发送一个确认包, 表明自己已经收到了客户端断开连接的请求, 但是还没有准备好关闭连接.

    发送完毕后, 服务器端进入 CLOSE_WAIT 状态, 客户端接收到确认包后进入 FIN_WAIT_2 状态, 等待服务器关闭连接

  3. 第三次挥手 (FIN=1, seq=y)

    服务器端准备好关闭连接时, 向客户端发送结束连接请求, FIN 置为 1

    发送完毕后, 服务器端进入 LAST_ACK 状态, 等待客户端的最后一个 ACK

  4. 第四次挥手 (ACK=1, ACKnum=y+1)

    客户端接收到来自服务器端的关闭请求, 发送一个确认包, 并进入 TIME_WAIT 状态, 等待可能出现的要求重传的 ACK 包.

    服务器端接收到这个确认包后, 关闭连接, 进入 CLOSED 状态.

    客户端等待了某个固定时间 (两个最大段生命周期, 2MSL, 2 Maximum Segment Lifetime)之后, 没有收到服务器端的 ACK, 认为服务器 已经正常关闭连接, 于是自己也关闭连接, 进入 CLOSED 状态.

1.2.4. 为什么要四次挥手

为双方好

  1. 保证接收端收到了 ACK 信息进入 CLOSED 状态
  2. 如果立即进入 CLOSED 状态, 且正好有连接使用的四元组件相同, 就会导致新的连接接收到旧连接的数据包. 总的来说就是让旧连接数据包消失在网络传输中.

1.2.5. 连接队列

  • 半连接队列: 储存 SYN 后的连接

  • 全连接队列: 储存 ACK 后的连接

    • 队列满策略: 由参数/proc/sys/net/ipv4/tcp_abort_on_overflow控制, 默认为0
      • 0: 全连接队列溢出, 服务端 Server 扔掉客户端 Client 发送的数据包信息 (客户端并不知道连接失败)
      • 1: 全连接队列移除, 服务端发送 RST 包到客户端 Client 强制断开连接 (客户端会知道自己被断开了)

1.2.6. TCP 延迟确认

TCP 会采用延迟确认的策略减少性能开销. 当接收到数据后会稍微等待下看有没有数据包需要发送, 如果有数据包返回就会顺带一起进行 ACK 确认, 当然若等待过程中没有数据包传输最后也会单独进行 ACK 确认, 这就是延迟确认.

1.2.7. (3) TCP 通过什么来保证可靠传输的?

  1. 确认和重传: 接收方收到报文就会确认, 发送方发送一段时间后没有收到确认就重传.
  2. 数据较远
  3. 数据合理分片和排序(接收方会缓存未按照顺序到达的数据, 重新排序后再交给应用层)
  4. 流量控制: 当接收方来不及处理发送方的数据, 能提示发送方降低发送的速率, 防止包丢失
  5. 阻塞控制: 当网络阻塞时, 减少数据的发送

1.2.8. (4) TCP与UDP区别, 分别在哪一层

都在运输层, 使用网络层的 IP 协议提供动力

  • UDP 特点
    • 无连接 (不需要握手挥手)
    • 非阻塞 (高并发)
    • 面向数据报 (数据报有长度, 一次发送一个数据报)
    • 支持多播和广播
    • 不可靠 (不提供确认, 重传等, 不保证顺序, 不保证能到达, 也不保证只到达一次)
  • TPC 特点
    • 面向连接
    • 阻塞
    • 流量控制
    • 可靠 (使用校验和, 确认和重传机制, 流量控制, 拥塞控制, 给数据分节排序)
    • 只支持单对单
    • 面向字节流, 数据

1.2.9. TCP 阻塞控制怎么实现?

拥塞: 是指数据发送速度超出网络所能承受的极限, 经常造成路由器丢包的现象

拥塞窗口cwnd(congestion window)

慢开始门限ssthresh状态变量

ssthresh的用法如下:

  • 当cwnd<ssthresh时,使用慢开始算法。
  • 当cwnd>ssthresh时,改用拥塞避免算法。
  • 当cwnd=ssthresh时,慢开始与拥塞避免算法任意

通过阻塞窗口实现的, 包含几种常见方法:

  1. 慢开始 (1开始, **增加, (拥塞控制: 到达上限速度变为++))

    TCP 开始发送报文时段先设置 cwnd = 1, 然后再逐渐增大 (*2 增加)

    发送方维持阻塞窗口, 阻塞窗口的大小取决于网络的阻塞程度, 是动态变化的.

    发送方让自己的发送窗口等于阻塞窗口, 另外考虑到接收方的接收能力, 发送窗口可能小于阻塞窗口

    慢开始的思路是, 不要一开始就发送大量数据, 先探测一下网络的阻塞程度, 也就是说由小到大逐渐增加阻塞窗口的大小

  2. 拥塞避免 (乘法减小, 加法增大)

    让拥塞窗口缓慢增长, 每经过一个往返时间 RTT 就把发送方的阻塞窗口 cwnd++, 而不是加倍, 这样阻塞窗口按线性规律缓慢增长

    拥塞窗口大于慢开始门限, 就执行拥塞避免算法

  3. 快重传

    发送方只要一连收到三个重复的确认时就应当重传对方尚未收到的报文. 而不必等到该分组的重传计时器到期.

  4. 快恢复 (门限上线减半, 然后从这一半开始++)

    当发送方连续收到三个重复确认时, 就执行 "乘法减少" 算法, 吧 ssthresh 门减半, 但是接下去并不执行慢开始算法

    考虑到如果网络出现拥塞的话就不会收到好几个重复的确认, 所以发送方现在认为网络可能没有出现拥塞. 所以此时不执行慢开始算法, 而是将 cwnd 设置为 ssthresh 减半后的值, 然后执行拥塞避免算法, 使 cwnd 缓慢增大

1.2.10. (3) TCP 传输过程中如何做流量控制? 扩大窗口和缩小窗口机制?

是指让发送方的发送速率不要太快, 让接收方来得及接收

主要思路是让发送方知道接收方当前的接收能力, 调整发送速率

当接收方告知还有空余缓存空间时, 发送方将扩大窗口, 反之减小窗口

原因

双方在通信的时候, 发送方和接收方的速率不一定是相等的, 如果发送方的速率太快, 会导致接收方处理不过来, 这个时候接收方只能够把处理不过来的数据放到 缓存区中, 如果缓存区满了发送方还在疯狂发送数据, 接收方只能把接收到的数据包丢掉, 极大的浪费网络资源, 所以需要控制发送方的发送速率, 让接收方 和发送方处于一种平衡状态才好, 对于发送方发送速率的控制, 称为流量控制.

控制方法

接收方每次接收到数据包, 可以在发送确定报文的时候, 同时告诉对方自己缓存区还剩多少是空闲的, 我们也把缓存区的剩余大小叫做接收窗口的大小, 用变量win表示

发送方收到之后, 会调整额自己的发送速率, 也就是调整自己发送窗口的大小, 当发送方收到窗口大小为0时, 发送方就会停止发送数据, 防止出现大量丢包情况的发生.

当接收方收到 接收窗口 win = 0 时, 这时发送方停止发送报文, 并且同时开启一个定时器, 每隔一段时间就发个测试报文去询问接收方, 看是否可以继续发送 数据, 如果可以, 接收方就告诉他此时接收窗口的大小. 如果接收窗口大小还是0, 则接收方再次刷新启动定时器.

窗口越大越好吗?

现在的 TCP 协议中窗口大小是不固定的, 如果接收窗口过小, 会严重浪费链路利用率, 增加丢包率. 当接收窗口到达某个值的时候, 再增大也不怎么会减少 丢包率了, 而且会更加消耗内存, 所以接收窗口的大小必须根据网络环境以及发送发的拥塞窗口来动态调整.

1.2.11. TCP 头信息

  • 16位源端口号 (Source port): 指定数据包归属某个应用
  • 16位目的端口号 (Destination port)
  • 32位序号 (Sequence number): 一次通信过程中某一个传输方向上的字节流的每个字节的编号, 通过这个来确认发送的数据有序.
  • 32位确认号 (Acknowledgment number): 用来响应 TCP 报文段, 给收到的 TCP 报文段的序号+1, 三握时还要携带自己的序号
  • 4位头部长度: 标识该 TCP 头部有多少个4字节, 共表示 15*4 = 60个字节
  • 6位保留
  • 若干个 Flags
    • SYN: 请求连接数据包标志 (三次握手时)
    • ACK: 确认数据包 (数据接收方收到数据包后确认同喜的数据包)
    • FIN: 断开数据包 (四次挥手时传递)
    • RST: 强制断开 (某些不合法操作时强制断开连接返回的数据包)
    • PSH: 传输层别缓存, 立即将数据交给应用层
  • 16位窗口大小 (Window Size): TCP 流量控制的一个手段, 告诉对端自己缓存区还能容纳多少字节
  • 校验和(Checksum): 作用在于接收方会根据这个数值来判断数据包的完整性.
  • 16 位紧急指针 (Urgent pointer): 一个正偏移量, 它和序号段的值相加表示最后一个紧急数据的下一字节的序号
  • 选项(最多40字节)
  • 数据

1.2.12. UDP 头信息

UDP 最小长度: 无数据情况下, 仅首部8字节 UDP 数据部分最小 0 字节 UDP 最大长度, 受长度字段16位的限制, 所以最大长度为 2**16 - 1 = 65535 字节 UDP 数据部分最大长度: UPD 最大长度 - IP 最小头部 - UDP 头部 = 2**16 - 20 -8 = 65507 字节

  • 16位源端口号
  • 16位目的端口号
  • 16位数据包长度
  • 16位校验和
  • 数据

1.2.13. IP 头信息是否了解

实际上指的是 TCP/IP 协议中的数据报结构

  • 4位版本号 (IPv4)
  • 4位头部长度: 标识头部有多少个字节, 最大 15*4 = 60个字节
  • 8位服务类型: 包含一个4位优先权字段: 最小延时, 最大吞吐量, 最高可靠性和最小费用
  • 16位总长度: 标识整个IP数据报的长度, 最大表示65535, 但由于 MTU 限制, 一般无法到达这个值.
  • 16 位标识: 唯一的标识数据包
  • 3位标识: (保留, DF禁止分片, MF更多分片)所以这个标志是为分片存在,DF设置时禁止分片所以如果数据报太大则发送失败。MF设置时,如果产生分片,除了最后一个分片,其他此片置1。
  • 13位分片偏移: 分片相对原始IP数据报开始处的偏移
  • 8位生存时间(TTL): 数据报到达目的地之前允许经过的路由跳跳数, 跳一下-1, =0丢弃
  • 16位头部校验和: 仅以CRC算法检验数据报头部在传输过程中是否损坏。
  • 32位源端口IP地址
  • 32位目的端口IP地址
  • 选项(可变长)记录路由,告诉途径得所有路由把IP填进来。 时间戳,告诉每个路由器都将数据报被转发的时间传进来。松散路由选择,指定一个路由器IP地址列表,必须按这个表发送,严格路由选择,数据报经过路由表。
  • 数据

1.2.14. IP, TCP, UDP 头部之间的关系

IP 头部在网络层组装和解析

TCP, UDP 头部在运输层组装和解析

1.2.15. SYN 攻击 (DDos攻击)

什么是 SYN 攻击

在三次握手的过程中, 服务器发送 SYN_ACK 之后, 收到客户端 ACK 之前的TCP连接称为 半连接状态 (half open connect). 此时服务器处于 SYN_RECD 状态, 需要客户端回复 ACK 才能进入 ESTABLISHED 状态.

SYN 攻击指的是, 攻击客户端在短时间内伪造出很多不存在的 IP 地址, 向服务器不断的发送 SYN 包, 服务器回复确认包, 并等待客户端的确认. 由于这些 IP 是不存在的, 服务器需要不断的重复发送直至超时, 这些伪造的 SYN 包将长时间占用未连接队列. 正常的 SYN 请求被丢弃, 导致系统运行缓慢, 严重的会导致 网络阻塞甚至系统瘫痪.

SYN 攻击是一种典型的 Dos/DDoS 攻击

如何检测 SYN 攻击

检测 SYN 攻击非常方便, 当你在服务器上看到大量的半连接状态时, 特别是 IP 地址是随机的, 基本上可以断定这是一次 SYN 攻击. 在 Linux/Unix 上 可以使用系统自带的 netstats 来检测 SYN 攻击.

netstat -n -p -t | grep SYN_RECV | grep :80 | wc -l

如何防御 SYN 攻击?

SYN 攻击不能完全被阻止, 除非将 TCP 协议重新设计. 我们所做的是尽可能减轻 SYN 攻击的危害, 常见的防御 SYN 攻击的方法有:

  • 缩短超时 (SYN Timeout) 时间
  • 增加最大半连接数
  • 过滤网关防护
  • SYN cookies 技术

1.2.16. keepalive 有什么用?

TCP 的连接, 实际上是一种纯软件层面的概念, 在物理层面并没有 "连接" 这种概念. TCP 通信双方建立交互的连接, 但是并不是一直存在数据交互, 有些连接会在数据交互完毕后, 主动释放连接, 而有些不会. 在长时间无数据交互的这段时间内, 双方都可能会出现掉电, 死机, 异常重启等各种意外, 当这些意外发生之后, 这些 TCP 连接并未来得及正常释放, 在软件层面上, 连接的另一方并不知道对端的情况, 它会一直维护这个长连接, 长时间的积累 会导致非常多的半打开连接, 造成端系统资源的消耗和浪费, 为了解决这个问题, 在传输层可以利用 TCP 的KeepAlive 机制实现来实现.

TCP KeepAlive 的基本原理是, 隔一段时间给连接对方发送一个探测包, 如果收到对方回应的 ACK, 则认为连接还是存活的, 在超过一定重试次数之后 还是没有收到对方的回应, 则丢弃该 TCP 连接.

局限性:

  1. TCP KeepAlive 检测的方式是发送一个 prbe 包, 会给网络带来额外的流量.
  2. 只能在内核层级检测连接的存活与否, 连接存活并不代表服务一定可用. 所以 TCP KeepAlive 对于应用层程序的价值相对较小, 一般程序会在应用层 自己实现自己的心跳功能.

1.2.17. TCP在哪一层? OSI 五层分别是什么? 各层功能是什么? 都有哪些协议?

TCP在运输层

  • 应用层:
    • HTTP, FTP, TELNET, SMTP, WWW, DNS
    • 应用层: 规定应用程序的数据格式
    • 表示层: 它对来自应用层的命令和数据进行解释,对各种语法赋予相应的含义,并按照一定的格式传送给会话层
    • 会话层: 是向两个实体的表示层提供建立和连接的方法
  • 运输层: 端口到端口, 用来区分数据应该到哪个应用上
    • TCP, UDP, SPX
  • 网络层: 提供路由和寻址功能, 使两端系统能够互联且决定最佳路径, 并具有一定的拥塞控制和流量控制功能, 互联网中不同子网之间通信规则
    • IP, IMP, ARP< RARP, OSPF, IPX, RIP, IGRP (路由器)
  • 数据链路层: 通过各种控制协议, 将有差错的物理信道变为无差错的, 能可靠传输数据帧的数据链路; 定义了 0和1 的分组方式
    • PP, FR, HDLC, VLAN, MAC (网桥, 交换机)
  • 物理层: 利用传输介质为数据链路层提供物理连接, 实现比特流的传输 (光缆, 电缆等)
    • RJ45, CLOCK, IEEE802.3 (中继器, 集线器)

1.2.18. close_wait 太多怎么处理? 为什么会出现这种情况? (Too many open files)

原因

四次挥手中, 服务端在第二次挥手进入 CLOSE_WAIT 状态后, 没有进一步发送 FIN 包给客户端, 导致服务端大量 CLOSE_WAIT 状态的 TCP 连接等待着. 服务端(被动关闭方)没有及时的发送第二个 FIN 包呆滞的 一般来说, 是程序代码本身出了问题, 导致连接无法走完整的四次握手断开.

主子进程共享 socket, close 不能完全关闭

1.2.19. UDP使用场景(计算机系统中使用UDP),在什么情况下优先考虑使用UDP。

  1. 网络通讯质量要求不高
  2. 要求网络通讯速度尽可能快

举例: QQ语音, QQ视频 (允许丢帧, 但是不容易接受重发导致的画面声音延迟)

1.2.20. TCP 使用场景

  1. 对网络通信质量要求高

举例: 发送邮件, 浏览网页, SSH 连接, QQ 文件传输

1.2.21. 如何使用 UDP 实现 TCP ?

实现 TCP 实际上就是指用 UDP 实现 TCP 的几个特性:

  1. 确认: 接收方收到包后会回复确认
  2. 超时重传: 超过时间后没有收到确认会发送重传
  3. 数据包排序: 对数据包进行排序
  4. 缓存区: 对未接受完整的数据包, 放入缓存区, 等待接收完整后拼装给应用层
  5. 流量控制和拥塞控制: 使用头信息实现滑动窗口, 用来流量控制和拥塞控制

1.2.22. 如何可靠化 UDP ?

  1. 确认重传机制
  2. 发送包有递增序号, 接收方发现中间丢包就要发重传请求
  3. 网络太差时要有发送窗口限制(流量控制)
  4. 接收方缓存区慢了要有停发机制

1.2.23. tcp发送数据时, 服务器宕机了会怎么样? 然后服务器又好了又会怎么样?

客户端会收不到 TCP 的确认包, 然后会尝试重传, 对应的有流量拥塞控制机制, 会逐渐减少发包量.

当达到设置的重试次数后, 将断开链接.

1.2.24. close_wait, time_wait

close_wait 在四次挥手的第一次接收方产生, 表明接收方接收到了请求方的关闭连接的请求, 但还没有准备好关闭连接. time_wait 在四次挥手的最后一次产生, 发送方在最后确认包发生后, 将进入 2MSL 的等待期, 在没有收到服务器端的 ACK, 认为接收方 已经正常的关闭连接了, 于是自己也关闭连接, 进入 CLOSED 状态

1.2.25. (2) select 和 epoll 的区别, epoll 如何实现不轮询?

都是 IO 多路复用机制. IO 多路复用就通过一种机制, 监听多个描述符, 一旦某一个描述符就绪(一般是读或者写就绪), 就能够通知程序进行相应的操作.

  • select: 通过数组来储存fd
    • 缺点
      • 单个进程可监听数量被限制, 一般为 1024 个(32位), 2048个(64位)
      • 查询复杂度 O(n), 每次都要轮询数组
  • poll: 通过链表来储存
  • epoll
    • 没有最大并发连接的限制
    • 查询复杂度 O(1), 通过管理活跃连接的方式来实现的

1.2.26. Socket 是什么

socket 是对 TCP/IP 协议族的一种封装, 从设计模式来讲, 就是一个门面模式. Socket 起源于 Unix, 可以看做是一种特殊的文件.

1.2.27. select 工作机制? 针对进程还是线程?

针对进程的, select 的核心是一组文件 fd(简称fds), 如果fds中的某个fd的状态符合要求(比如变得可读可写等, 或者有异常等等), select 就从 等待中返回.

1.2.28. (4) http 与 https 的区别, 加密怎么加的? (ca证书作用)

超文本传输协议, 超文本安全传输协议, 都在应用层, 基于 TCP 协议.

  • 区别
    • https 协议需要 ca 申请证书, 一般免费的证书较少, 需要一定的费用
    • http 是明文, https 是具有安全性的 ssl 加密传输协议
    • http 和 https 使用完全不同的连接方式, 使用的端口也不一样, 80, 443
    • http 连接很简单, 无状态; https 协议是由 ssl+http 协议构架你的可进行加密传输, 身份认证的网络协议, 比 http 安全
  • https 流程
    • 客户端发起 HTTPS 请求
    • 传送证书给客户端
    • 客户端对证书进行解析验证
    • 传送加密信息 (随机密码)
    • 服务端解密信息 (随机密码)
    • 双方使用 随机密码 进行对称加密通信
  • https 多使用服务器资源
    • http 连接
      • 握手 3 个包
      • http -> tcp -> ip
    • https 连接
      • 握手 3 个包, SSL握手 9 个包, 一共 12 个包
      • http -> SSL or TLS -> tcp -> ip
      • 连接建立后就和 tcp 一致, 只会在对称加密时对 cpu 造成微小的影响
  • https 优点
    • SEO
    • 安全性
  • https 缺点
    • 证书收费
    • 增加服务器负担

1.2.29. SSL 作用

SSL 协议是一种网络安全协议, 它在传输通信协议(TCP/IP)上实现的一种安全协议, 采用公开秘钥技术

  • 作用
    • 认证用户和服务器, 保证数据发送到正确的客户机和服务器
    • 加密数据以防止数据中途被窃取
    • 维护数据的完整性, 确保数据在传输过程中不被改变

1.2.30. (3) http 各种返回码, 401 和 406 的区别?

  • 1xx 信息型, 服务器收到请求, 需要请求者继续操作
  • 2xx 成功型, 请求成功收到, 理解并处理
  • 3xx 重定向, 需要进一步的操作完成请求
  • 4xx 客户端错误, 请求包含语法错误或者无法完成请求
    • 401 表示未认证, 没有带上必要的凭据
    • 406 请求的资源内容特性无法满足请求头中的条件, 因而无法生成响应实体, 该请求不可接受
  • 5xx 服务器错误, 服务器再处理请求的过程中发生了错误

1.2.31. 一个 10M 大小的 buffer 里存满了数据, 现在要把这个 buffer 里的数据尽量发送出去, 可以允许部分丢包, 请问用 tcp 好 还是 udp 好? 为什么?

使用 UDP 可以保证速度, 没有重传机制, 没有阻塞机制, 保证最快速度

使用 TCP 可以保证尽量不丢包, 丢包会重传, 在网络环境差的情况下推荐使用

1.2.32. 一个完整的 Http 请求会涉及到哪些协议?

应用层: HTTP 运输层: TCP 网络层: IP 数据链路层: ARP (地址解析协议), RARP (逆地址解析协议)

1.2.33. (2) POST GET HEAD 区别

  • 都包含请求头请求行, POST 多了请求 body
  • GET 多用来查询, 请求参数直接放在 URL 后面, POST 是放在报文内的, 用户无法直接看到
  • GET 提交的数据长度是有限制的, 而 POST 没有限制
  • HEAD 只请求页面的首部

1.2.34. 一次http连接成功后断开重新及进行第二次http连接, 是否需要重新tcp连接?

主要看 http 连接时有没有使用 HTTP keep-alive, 如果使用了的话, 不会重新建立 tcp 连接.

1.2.35. lnmp 网站请求过程中做了什么?

  1. DNS 解析, 将域名解析成 IP
  2. tcp 连接
  3. 发起 HTTP 请求
  4. 请求到达 Nginx 处理
  5. Nginx worker 处理, 转发给 fast-cgi 模块处理
  6. 通过 fastcgi_pass 转发给 php-fpm 处理
  7. php-fpm master 指派 worker 进程进行请求处理, 如果没有可用进程, 则返回 502
    • ZendVM 处理阶段
      • 词法语法分析, 生成 AST
      • 解析 AST, 生成 zend_op_array
      • ZendVM 执行 zend_op_array
  8. worker 处理请求, 如果超时, 则返回 504
  9. 请求处理结束, 返回结果给 nginx

1.2.36. HTTP 1.0, HTTP 1.1, HTTP 2.0

  • 长连接
    • 1.0 需要使用 keep-alive 告诉服务器需要建立长连接
    • 1.1 默认支持长连接
  • 节约带宽
    • 1.1 支持只发送 header 信息
  • HOST 域
    • 1.1 开始支持 host 域, 使同一 ip:port 能支持多个虚拟站点
  • 多路复用
    • 2.0 开始多路复用技术, 一个连接并发处理多个请求, 并发请求的数量比 1.1 大了好几个数量级
  • 数据压缩
    • 1.1 不支持 header 数据的压缩
    • 2.0 使用 HPACK 算法对 header 的数据进行压缩
  • 服务器推送
    • 2.0 可以在web请求数据的时候, 将客户端需要的资源一起推送到客户端.
  • 断点续传
    • 1.1 开始通过 [Range: bytes] 来控制从文件头偏移多少字节来传输文件

1.2.37. 从一台 server 访问另一台 server 出现 unreachable 报错如何排查网络那个部分出现错误。

1.2.38. csrf 原理

跨站点请求伪造(Cross-site request forgery), 是一种网络攻击方式.

CSRF 攻击利用网站对于用户网页浏览器的信任, 挟持用户的一登录身份, 去执行非用户本意的操作

  • 防护
    • 只使用 JSON API, 让 form 表单伪造提交无效
    • 验证 HTTP Referer
    • 在请求地址中添加 token 验证

1.2.39. WebSocket 内容? 属于那一层? 基于什么实现的?

网络协议的一种, 应用层, 是 HTTP 协议的一种补充

  • 特点
    • 可以主动向客户端推送信息
    • 建立在 TCP 协议之上
    • 与HTTP协议有着良好的兼容性, 默认端口也是 80, 443, 并且握手阶段采用 HTTP 协议.
    • 数据格式比较轻量, 性能开销小, 通信高效
    • 可以发送文本, 也可以发送二进制数据
    • 没有同源限制, 可以与任意服务器通信
  • 借用 HTTP 来握手
    • 请求 Headers
      • Upgrade: websocket
      • Connection: Upgrade
      • Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
      • Sec-WebSocket-Protocol: chat, superchat
      • Sec-WebSocket-Version: 13
    • 响应 Headers
      • Upgrade: websocket
      • Connection: UPgrade
      • Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
      • Sec-WebSocket-Protocol: chat
    • 握手完毕

1.2.40. 访问百度的过程中, 各层做了什么

  • 应用层: HTTP 协议, 生成 HTTP 报文, 发送请求
  • 传输层: TCP 协议, 对 HTTP 报文进行分割, 并在分割后的报文打上标记序号及端口号后转发给网络层
  • 网络层: IP 协议, 增加作为通信目的地的 MAC 地址后转发给链路层
  • 链路层: 以太网首部 , 给这些数据加上以太网首部并进行发送, 生成的以太网数据包将通过物理层传输给接收端

1.2.41. 浏览页面过程中, client和server做了什么?

  • client
    • 发送请求
    • 渲染页面
  • server
    • 接收请求
    • 响应数据生成 response 返回

1.2.42. Accept 发生在TCP三次握手的哪个阶段? connect, listen 函数?

服务器端: socket->bind->listen->accept

客户端: socket->connect

accept 发生在三次握手后, 客户端和服务器建立了 tcp 连接, 这时可以调用 accept 函数获得此连接

1.2.43. 基于 UDP 的应用层协议有什么? 基于 TCP 的有什么?

  • UDP
    • NFS (网络文件系统)
    • SNMP (简单网络管理协议)
    • DNS (主域名称系统)
    • TFTP (通用文件传输协议)
  • TCP
    • HTTP
    • Telnet
    • FTP
    • SMTP

1.2.44. 503 状态码怎么解决

服务器处于维护或者过载状况, 这个状况是暂时的, 并且将在一定时间后恢复. 如果能够预计延迟时间, 可以在 Retry-After 表明这个延迟时间. 如果没有 标明这个时间, 那么可以当做 500 处理.

1.2.45. 快重传的作用

快重传是 TCP 拥塞算法中的一条, 当连续收到三条同一个报文的确认回复后, 发送端可以直接对下一个包进行重试发送. 而不用等重传计时器到期.

1.2.46. http 缓存机制有哪些? 什么是CDN? header中涉及到缓存的字段有哪些?

  • 机制
    • 强缓存: 当有缓存时, 直接使用缓存, 不需要对比
      • Expires (HTTP 1.0): 缓存过期时间, 超过时间意味着资源过期了, 有 Cache-Control 时会优先使用 Cache-Control
      • Cache-Control: 可以由多个字段组成
        • max-age: 指定过期时长, 单位为秒,
        • s_maxage: 同 max-age, 覆盖 max-age, Expires, 但仅适用于共享缓存, 在私有缓存中被忽略
        • private: 响应只能被单个用户(操作系统用户或浏览器用户)缓存, 是非共享的, 不能被代理服务器缓存
        • public: 声明响应可以被任何对象(操作系统用户或浏览器用户)缓存, 是共享的
        • no-cache: 强制所有缓存了该响应的用户, 在使用已缓存的数据前, 发送带验证器的请求到服务器. 不是字面上的不缓存
        • no-store: 禁止缓存, 每次请求都需要向服务器重新获取数据
    • 协商缓存: 当缓存到期时, 并不意味着资源一定发生了改变, 第一次请求时会将数据和响应头部标识存储起来, 再次请求时会带上这些头部字段, 服务端验证是否可用. 如果返回 304 Not Modified 代表资源没有发生改变, 可以继续用. 返回 200 相当于又请求了一次, 替换旧资源
      • Last-modified/If-Modified-Since: 服务器端资源最后修改时间
      • Etag/If-None-Match: 服务器端生成的一端 hash 字符串, 第一次响应中会带有, 之后的请求中带上 If-None-Match, 服务器检查 Etag, 返回 304 或 200.

由于 HTTP 协议是无状态的协议, 所以服务端需要记住用户的状态时, 就会使用 Session 来保存用户数据.

Session 是保存在服务端的, 保存方式有多种: 文件, 数据库, 缓存, 内存都有.

会产生 Session ID 储存在客户端中, Cookie 会在客户端请求服务端时, 被附带在头信息上, 这样服务端可以获取到这一部分的信息, 包括 Session ID, 就可以查询到对应的 Session , 区分出用户的数据

1.2.48. html 页面, 怎么与后端交互? 流程是什么? 涉及到哪些组件?

  • 交互方式: ajax 请求后端你的 restful api, 使用 json 数据交互
  • 流程: 后端开发 api, 前端使用 ajax 技术向 api url 发送 http 请求, 获取到响应数据
  • 涉及组件: HTTP 客户端, Web 服务器

1.2.49. put, post 实现有什么优缺点?

  • put 定义用来更新数据
  • post 定义用来创建数据

1.2.50. 前后端分不分离有什么区别? 有什么优缺点?

前后端只通过 JSON 来交流, 组件化, 工程化不需要依赖后端去实现.

前端: 只负责 View 和 Controller 层 后端: 只负责 Model 层, 业务处理/数据等

  • 优点
    • 分清前后端职责
    • 提高开发效率, 前后端可以同步进行开发
    • 增大前端的开发空间, 前后端可以分开优化
    • 更利于分布式
    • 减少对于服务器的压力
    • 后端的错误不会直接反映到前台
    • 更便于测试
  • 缺点
    • 不利于 SEO
    • 人员问题
    • 产品迭代问题
    • 前端需要学习业务

1.2.51. 常见web攻击有哪些? csrf 攻击了解吗?

  • XSS: 跨站点脚本攻击, 指攻击者在网页中嵌入恶意脚本程序
  • CSRF: 跨站点请求伪造
  • SQL: 注入
  • DDoS: TCP 连接握手时伪造大量的 IP 对服务器发起握手请求, 由于 IP 是伪造的, 导致这些包大量占用服务器未连接队列资源, 正常的 TCP 握手连接 可能被丢弃.

1.2.52. restful 的作用? 有哪些优点和缺点?

restful 是一种风格,

  1. 状态无关 —— 确保系统的横向拓展能力
  2. 超文本驱动,Fielding的原话是”hypertext-driven" —— 确保系统的演化能力
  3. 对 resource 相关的模型建立统一的原语,例如:uri、http的method定义等 —— 确保系统能够接纳多样而又标准的客户端

  4. 优点

    • 开放性高
    • 行为和资源分离, 更容易理解
    • 提出使用版本号, 更加规范
  5. 缺点
    • 对后端开发人员要求高, 业务逻辑有时难以被抽象为资源的增删改查
    • 对前端开发人员不友好, API粒度较粗, 难以查询符合特殊要求的数据, 同样的业务比普通的 API 需要请求更多次 HTTP 请求

1.2.53. nginx 达到上限了怎么办? 怎么对 nginx 负载均衡? dns ?

  1. 做 nginx 集群
  2. DNS 均衡负载, 请求分发到不同的 nginx 主机地址上

1.2.54. 拥塞控制的算法有哪几种?慢开始前期是指数型增长还是线性增长?

  • 慢开始
    • 1开始指数增长, 到达限制进入拥塞避免算法
  • 拥塞避免
    • 到达阈值后开始 ++
    • 进入拥塞状态后直接减半, cwnd 设置成1, 并进入快恢复算法
  • 快重传
    • 如果假设重复阈值为3,当发送方收到4次相同确认号的分段确认(第1次收到确认期望序列号,加3次重复的期望序列号确认)时,则可以认为继续发送更高序列号的分段将会被接受方丢弃,而且会无法有序送达。发送方应该忽略超时计时器的等待重发,立即重发重复分段确认中确认号对应序列号的分段。
  • 快恢复
    • 乘法减小, 加法增大

1.2.55. websocket能做负载均衡么?

可以使用 nginx 来做均衡负载

1.2.56. nginx为什么性能很高

  • 多进程+异步非阻塞方式(IO多路复用 epoll)
  • 单个 worker 中使用单线程, 降低了上下文环境切换损耗, 也不需要考虑并发问题

1.2.57. 接收方的读缓冲区为0,当读缓冲区读完的时候,发送方如何知道该发送了?

发送端会在接收方反馈缓存区慢时, 设置一个定时器, 定时查询接收方有多少缓冲区, 来判断是否可以发送数据了

1.2.58. websocket 是怎么实现服务器往客户端推送消息的?

TCP 建立的全双工通信通道

1.2.59. Http 协议为什么不支持推送?

HTTP 2.0 支持主动推动

不支持推送是由于协议规定的, HTTP 定义了一 request 一 response 的操作, 所以不能够主动推送

TCP 协议是一个双工协议, 也就是说: 基于 TCP 的服务器都具有主动推送的功能, 但是 HTTP 协议自身定义的规则不允许推送

1.2.60. select poll epoll 比较

  • select
    • 查询 fd_set 中, 是否有就绪的 fd, 可以设置一个超时时间, 当有 fd (File description)就绪或超时返回
    • fd_set 是一个位集合, 是在编译内核时的常量, 默认大小为 1024
    • 特点
      • 连接数限制: fd_set 可以表示的 fd 数量太小了
      • 线性扫描: 判断 fd 是否就绪, 需要遍历一遍 fd_set
      • 数据复制: 用户空间和内核空间, 复制连接就绪状态信息
  • poll
    • 解决了连接数限制
    • poll 中将 select 中的 fd_set 替换成了一个 pollfd 数组
    • 数据复制: 用户控件和内核空间, 复制连接就绪状态信息
  • epoll: event 事件驱动
    • 事件机制: 避免线性扫描, 为每个fd, 注册一个监听事件, fd变为就绪时, 将 fd 添加到就绪链表
    • fd 数量, 无限制(OS级别的限制, 单个进程能打开多少个 fd)

1.2.61. epoll 水平触发和边缘触发

  • 水平触发(level-trggered)
    • 只要文件描述符关联的读内核缓冲区非空,有数据可以读取,就一直发出可读信号进行通知, 当文件描述符关联的内核写缓冲区不满,有空间可以写入,就一直发出可写信号进行通知 LT模式支持阻塞和非阻塞两种方式。epoll默认的模式是LT。
  • 边缘触发(edge-triggered)
    • 当文件描述符关联的读内核缓冲区由空转化为非空的时候,则发出可读信号进行通知, 当文件描述符关联的内核写缓冲区由满转化为不满的时候,则发出可写信号进行通知

1.2.62. epoll 使用的数据结构

  • 红黑树: 储存所有socket
  • 链表: 储存所有已就绪的事件

1.2.63. epoll 高效的本质

  • 减少了用户态和内核态的文件句柄拷贝
  • 减少了对可读可写文件句柄的遍历
  • mmap 加速了内核与用户空间的信息传递,epoll是通过内核与用户mmap同一块内存,避免了无谓的内存拷贝
  • IO性能不会随着监听的文件描述的数量增长而下降
  • 使用红黑树存储fd,以及对应的回调函数,其插入,查找,删除的性能不错,相比于hash,不必预先分配很多的空间

1.2.64. LVS 和 Nginx 分别作用在 osi 哪一层?

LVS 只作用于运输层

Nginx 可以作用于运输层, 还可以作用于应用层

1.2.65. 负载均衡算法

在不同的网络层上, 可以做不同的均衡负载

  • 应用层: 根据虚拟的 url 或 IP, 主机名接收请求, 再转向响应的处理服务器

    • 所谓七层负载均衡,也称为“内容交换”,也就是主要通过报文中的真正有意义的应用层内容,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。
    • 以常见的 TCP 为例,负载均衡设备如果要根据真正的应用层内容再选择服务器,只能先代理最终的服务器和客户端建立连接(三次握手)后,才可能接受到客户端发送的真正应用层内容的报文,然后再根据该报文中的特定字段,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。负载均衡设备在这种情况下,更类似于一个代理服务器。负载均衡和前端的客户端以及后端的服务器会分别建立 TCP 连接。所以从这个技术原理上来看,七层负载均衡明显的对负载均衡设备的要求更高,处理七层的能力也必然会低于四层模式的部署方式。
    • 对应的负载均衡器称为七层交换机(L7 switch),除了支持四层负载均衡以外,还有分析应用层的信息,如 HTTP 协议 URI 或 Cookie 信息,实现七层负载均衡。此种负载均衡器能理解应用协议。
    • 应用:
      • haproxy:天生负载均衡技能, 全面支持7层代理, 会话保持, 标记, 路径转移
      • nginx: 只在 http 协议和 mail 协议上功能比较好, 性能与 haproxy 差不多
      • apache: 功能较差
      • MySQL proxy: 功能尚可
  • 运输层: 在网络层负载均衡的基础上, 用 ip + port 接收请求, 再转向对应的机器

    • 以常见的 TCP 为例,负载均衡设备在接收到第一个来自客户端的 SYN 请求时,即通过上述方式选择一个最佳的服务器,并对报文中目标 IP 地址进行修改(改为后端服务器 IP),直接转发给该服务器。TCP 的连接建立,即三次握手是客户端和服务器直接建立的,负载均衡设备只是起到一个类似路由器的转发动作。
    • 对应的负载均衡器称为四层交换机
    • 应用
      • F5: 硬件负载均衡器, 功能很好, 但是成本很高
      • LVS: 重量级的四层负载软件
      • Nginx: 轻量级的四层负载软件, 带缓存功能, 正则表达式较灵活
      • haproxy: 模拟四层转发, 较灵活
  • 网络层: 一般采用虚拟 IP 地址的方式, 外部对虚拟的 IP 地址请求, 负载均衡接收到后分配后端实际 IP 地址响应

1.3. 网络不可达排查流程

1.4. TCP 关闭连接

1.5. TCP 最多有几个连接 (fd, 四元组ip port 限制)

Client:

每个 TCP 连接占用一个文件描述符(端口), 本地最大端口数量为 65536 个, 端口0有特殊作用, 故最多能创建 65535 个 TCP 连接.

Server:

Server 启动后端口占用固定, 故最大 TCP 连接数等于 客户端ip数量 * 客户端port数量 2^48 个

1.6. 长连接基于 TCP 怎么实现的

TCP 握手后使用完不断开连接, 后续发包复用该连接.

维持连接:

TCP 层 KeepAlive 参数. 应用层订单发送心跳包.

1.7. UDP 与 TCP 可以同时监听一个端口吗?为什么

可以

sockaddr 结构包含 协议, IP, 端口. 由于协议的不同, 同一个端口下可以区分监听的是 TCP 还是 UDP

1.8. QUIC 协议

是一种快速 UDP 互联网连接协议,是由 google 提出的使用 udp 进行多路并发传输的协议。

相对于现在比较广泛的 http2 + tcp + tls 协议有以下优势:

  1. 减少了 TCP 三次握手以及 TLS 握手时间。
  2. 改进的拥塞控制。
  3. 避免队头阻塞的多路复用 TCP 协议的序列号导致的。
  4. 连接迁移
  5. 向前冗余纠错

  6. 连接建立时延低

TCP 三次握手需要 1.5RTT建立连接 TLS 握手需要 3RTT 而 QUIC 由于建立在 UDP 基础上,还实现了 0RTT的安全握手,所以在大部分情况下,只需要 0 RTT 就能实现数据发送。

  1. 改进的拥塞控制

TCP 包含四个算法: 慢启动,拥塞避免,快速重传,快速恢复

而 QUIC 协议默认使用当前 TCP 协议的 Cubic 拥塞控制算法, 同时还支持多种拥塞控制算法。

特色在于:

  • 可插拔
    • 基于应用层实现的拥塞控制算法,不需要操作系统、内容的支持。
    • 可以通过程序决定使用哪一种拥塞控制
    • 不需要停机和升级就可以切换拥塞控制算法应对多种场景
  • 单调递增的 Packet Number
    • TCP 重传时使用相同 Sequence Number, 不好判断是产生了重传还是正常数据;而 QUIC 重传的包也是递增后的序号。可以加快重传场景的判断。
    • 重传使用包内的 offset 偏移来判断数据归属位置,可以很方便的将数据补充到原来的数据流中。
  • 更多的 Ack Block
    • 在丢包率较高的场景下, 可以提升网络的回复速度,减少重传量
  • 基于 Stream 和 Connection 级别的流量控制
    • Stream 可以理解为一条 HTTP 请求
    • Connection 类比一条 TCP 连接。多路服用意味着在一条 Connection 上会同时存在多条 Stream。
    • 即对单个 Stream 进行控制, 又对所有 Stream 进行总体控制。
  • 队头阻塞优化
    • HTTP2 多路复用的 Stream 一个阻塞时,会使其他 Stream 也阻塞
    • QUIC Stream 阻塞只会影响自己
  • 加密认证的报文
    • 报文头部经过认证
    • 报文 Body 经过加密
  • 连接迁移
    • 四元组(源IP, 源端口,目标IP,目标端口),当一个元素变化时,连接依然维持着,保持业务不中断
    • 实现方式为: QUIC 不在以四元组作为标识,而是以一个 64 位随机数ID 做标识.
  • 向前冗余纠错
    • 重要的包丢失时,可以通过包的冗余数据恢复上一个包

场景:

  1. 提升连接建立速度
  2. 优化弱网环境下的使用体验
  3. 优化网络频繁切换下的使用体验
  4. 需要根据不同场景切换拥塞控制算法时

results matching ""

    No results matching ""