Skip to content

基础-网络TCP与HTTP

大类:计算机基础 · 共 56 题 · 检索页定位

选择题(28)

q162 · 简单

关于 HTTPS 的描述,下列哪一项是正确的?
A. HTTPS 默认使用 443 端口,通过 TLS 对传输数据加密,客户端会校验服务器证书以防止中间人攻击
B. HTTPS 中客户端校验证书的主要目的是验证客户端自己的身份
C. HTTPS 既不使用对称加密也不使用非对称加密,只靠哈希算法保证安全
D. 使用 HTTPS 后就彻底杜绝了 DNS 劫持的可能

参考答案要点
  • 正确答案 A. HTTPS 默认使用 443 端口,通过 TLS 对传输数据加密,客户端会校验服务器证书以防止中间人攻击
来源:[javaguide.cn](https://javaguide.cn/cs-basics/network/other-network-questions.html)

q163 · 简单

HTTP 状态码 301 和 302 的区别,正确的是?
A. 301 表示临时重定向,302 表示永久重定向
B. 301 表示永久重定向,302 表示临时重定向
C. 301 和 302 都表示永久重定向,区别仅在于是否允许改写请求方法
D. 301 属于服务端错误码,302 属于客户端错误码

参考答案要点
  • 正确答案 B. 301 表示永久重定向,302 表示临时重定向
来源:[javabetter.cn](https://javabetter.cn/sidebar/sanfene/network.html)

q164 · 中等

TCP 四次挥手过程中,主动关闭方发送最后一个 ACK 之后进入的状态,以及该状态存在的主要原因是?
A. 进入 CLOSE_WAIT 状态;等待对方重传 FIN
B. 进入 TIME_WAIT 状态;等待 2MSL,确保最后的 ACK 能到达对方,并让本连接的旧报文在网络中消逝
C. 进入 FIN_WAIT_2 状态;等待对方发送 FIN 报文
D. 进入 LAST_ACK 状态;等待对方回复 ACK 后关闭

参考答案要点
  • 正确答案 B. 进入 TIME_WAIT 状态;等待 2MSL,确保最后的 ACK 能到达对方,并让本连接的旧报文在网络中消逝
来源:[javabetter.cn](https://javabetter.cn/sidebar/sanfene/network.html)

q345 · 中等

服务重启时 bind 报 Address already in use,常见原因是旧连接仍处于 TIME_WAIT 占用了端口。关于 SO_REUSEADDR 选项,下列说法正确的是?
A. SO_REUSEADDR 允许 bind 处于 TIME_WAIT 状态的地址,服务重启可立即成功;但 ESTABLISHED/LISTEN 状态的连接仍不能被抢占
B. SO_REUSEADDR 设置后,两个进程可以同时 bind 并 listen 同一个端口,内核在进程间做负载分担
C. 只有客户端需要设置 SO_REUSEADDR,服务端监听端口不需要
D. 设置了 SO_REUSEADDR 后,主动关闭方就不再进入 TIME_WAIT 状态

参考答案要点
  • TIME_WAIT 占用四元组导致重启 bind 失败,SO_REUSEADDR 允许复用该地址立即重启,是服务端必设项
  • B 描述的是 SO_REUSEPORT(Linux 3.9+):多进程绑同一端口由内核哈希分流,nginx/docker 常用,与 SO_REUSEADDR 是两个选项
  • SO_REUSEADDR 不影响 TCP 状态机,TIME_WAIT 照样存在,只是允许 bind;不能抢占活跃连接
  • 追问:为什么 TIME_WAIT 默认是 60s(2MSL,MSL=30s)、客户端端口耗尽与连接池的关系
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_optimize.html)

q349 · 中等

关于 HTTP/3 与 QUIC 协议,下列说法不正确的是?
A. QUIC 建立在 UDP 之上,在用户态实现可靠传输、拥塞控制与多路复用,避免了内核协议栈升级困难
B. QUIC 使用 Connection ID 标识连接,客户端 IP 变化(如 WiFi 切 4G)后连接仍可复用,实现连接迁移
C. QUIC 消除了 HTTP/2 中 TCP 层的队头阻塞,因此 HTTP/3 应用中不存在任何形式的队头阻塞
D. QUIC 内置 TLS 1.3,传输层握手与加密握手合并,首次连接 1-RTT,会话恢复可 0-RTT

参考答案要点
  • C 过于绝对:传输层 Stream 间队头阻塞被消除,但应用层仍可能存在(如浏览器对关键资源的依赖、Stream 优先级调度),经典面试陷阱
  • A 正确:QUIC 传输功能在用户态实现,迭代不需要改内核,这是选 UDP 而不是再造 TCP 的主因
  • B 正确:连接以 CID 标识而非四元组,网络切换不断链
  • D 正确:QUIC 把 TLS1.3 握手消息嵌进自己的帧里,一次往返同时完成传输与加密握手
来源:[xiaolincoding.com](https://xiaolincoding.com/network/2_http/http3.html)

q356 · 简单

关于 TCP 与 UDP 的区别以及可靠传输,下列说法正确的是?
A. TCP 面向字节流因此存在粘包问题;UDP 面向报文保留消息边界,所以用 UDP 传输应用消息一条都不会丢
B. UDP 本身不可靠,基于 UDP 不可能实现可靠传输;QUIC 之所以可靠是因为它底层改用了 TCP
C. TCP 通过序列号、确认应答、超时重传、流量控制与拥塞控制保证可靠;要在 UDP 上实现可靠传输需在应用层自己做序列号、确认重传与拥塞控制,典型例子是 QUIC
D. UDP 头部有 20 字节,TCP 头部只有 8 字节,所以 UDP 的协议开销更大

参考答案要点
  • A 前半句对、后半句错:UDP 不粘包但可能丢包、乱序,不保证送达——典型的半对选项
  • B 错:QUIC 全程基于 UDP,可靠传输(重传/拥塞控制/流控)全部在用户态自己实现
  • D 正好说反:TCP 固定头部 20 字节,UDP 头部固定 8 字节
  • 延伸:TCP 适用于要求可靠有序的 HTTP/RPC/邮件;UDP 适用于实时音视频、DNS、游戏;音视频常用应用层 FEC+JitterBuffer 在 UDP 上做弱可靠
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/quic.html)

q478 · 困难

关于 TCP 的 Nagle 算法与延迟确认(delayed ACK)的相互作用,下列说法正确的是?
A. 两者配合默契,小包交互场景吞吐一定更高
B. TCP_NODELAY 的作用是关闭接收端的延迟确认,让对端立即回 ACK
C. Nagle 在发送端攒小包:只要有未确认的小段,后续小数据先缓存;若接收端又延迟发 ACK,双方可能互相等待,出现几十毫秒级的停顿;对低延迟请求-响应场景(Redis、SSH、游戏)通常用 TCP_NODELAY 关闭 Nagle
D. Nagle 算法在发送端与接收端各运行一份

参考答案要点
  • 正确答案 C. Nagle(发送端攒包)与 delayed ACK(接收端推迟确认)叠加是经典的 40ms 级延迟问题,低延迟场景应设置 TCP_NODELAY
  • A 两者叠加恰恰制造互相等待的停顿;B TCP_NODELAY 影响的是发送端是否攒包,不管接收端 ACK 时机
  • D Nagle 是发送端算法,延迟确认才是接收端行为
来源:synthesized

q479 · 中等

TLS 1.3 相比 TLS 1.2 在握手上的核心改进,正确的是?
A. TLS1.3 需要 2-RTT,TLS1.2 只需 1-RTT
B. TLS1.3 把密钥交换材料提前合并进 Hello 消息,完整握手降为 1-RTT;会话恢复场景还能 0-RTT 提前发送应用数据(但 0-RTT 数据存在重放攻击风险,需业务幂等)
C. TLS1.3 重新引入静态 RSA 密钥交换以提升兼容性
D. TLS1.3 的握手报文全程明文以减少开销

参考答案要点
  • 正确答案 B. 1.3 将 Hello 与密钥交换合并实现 1-RTT;PSK 会话恢复支持 0-RTT 早发,但早发数据可能被重放
  • A 方向反了:TLS1.2 完整握手约需 2-RTT,1.3 降到 1-RTT
  • C 1.3 删除了静态 RSA 等不具备前向安全的套件,只保留 (EC)DHE/PSK;D 1.3 在 ServerHello 之后即进入加密
来源:[xiaolincoding.com](https://www.xiaolincoding.com/network/3_tcp/tcp_tls.html)

q480 · 简单

HTTP 方法的幂等性,下列说法正确的是?
A. GET、PUT、DELETE 在语义上幂等(重复执行效果不变),POST 不幂等——重复提交可能创建多笔订单
B. 所有 HTTP 方法天然幂等,重复调用没有副作用
C. POST 也是幂等的,因为每次调用都会返回 200
D. PUT 不幂等,PATCH 才是幂等的

参考答案要点
  • 正确答案 A. 幂等指同一请求多次执行与一次执行效果相同;GET/PUT/DELETE 语义幂等,POST 每次都可能产生新资源
  • B 幂等性正是自动重试安全性的判断依据,POST 直接重试有重复下单风险
  • C 状态码与幂等性无关;D PUT 整体替换语义幂等,PATCH 是否幂等取决于具体实现(如增量累加就不幂等)
来源:[developer.mozilla.org](https://developer.mozilla.org/zh-CN/docs/Glossary/Idempotent)

q481 · 中等

Set-Cookie 的 HttpOnly、Secure、SameSite 三个属性分别起什么作用?
A. SameSite=None 是浏览器默认值,且最安全
B. HttpOnly 禁止浏览器 JS(如 document.cookie)读取该 Cookie,缓解 XSS 窃取;Secure 要求仅通过 HTTPS 传输;SameSite 限制跨站请求携带(Strict/Lax),是缓解 CSRF 的手段(None 必须配合 Secure)
C. HttpOnly 禁止 Cookie 通过非 HTTPS 发送;Secure 防止 JS 读取;SameSite 加密 Cookie 内容
D. 三者都只影响 Cookie 的过期时间

参考答案要点
  • 正确答案 B. 三个属性分别对应:防 JS 读取、防明文传输、防跨站自动携带
  • C 两个属性张冠李戴,SameSite 也不加密内容;D 过期由 Expires/Max-Age 控制
  • A 现代浏览器默认策略趋向 Lax,None 恰恰是限制最宽松的取值
来源:[developer.mozilla.org](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie)

q482 · 中等

Nginx 反代日志里大量 502 与 504。两者的含义与排障方向,正确的是?
A. 502 Bad Gateway 常见原因是上游进程崩溃/拒绝连接/返回无效响应;504 Gateway Timeout 是上游在超时时间内没有返回响应——排查 502 先看上游进程存活与端口,排查 504 先看慢在哪(慢 SQL、下游阻塞)以及超时配置
B. 502 表示上游处理超时,504 表示上游返回了格式错误的响应
C. 502 是客户端侧错误,504 是服务端成功响应
D. 两者含义相同,可以互换使用

参考答案要点
  • 正确答案 A. 502=网关收到无效响应(上游崩了、连不上),504=网关等待上游超时(上游活着但太慢)
  • B 两个状态码的含义正好说反;C 5xx 都是服务端/网关侧错误,不存在「成功」
  • D 语义明确不同,排障路径也不同:一个查存活,一个查慢
来源:[developer.mozilla.org](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status)

q483 · 中等

名字很像的「TCP keepalive」与「HTTP Keep-Alive」,下列说法正确的是?
A. 两者是同一机制在两层的叫法,配置一个另一个自动生效
B. HTTP Keep-Alive 用来检测断线,TCP keepalive 用来复用连接
C. 打开 HTTP Keep-Alive 后,内核的 TCP keepalive 自动关闭
D. TCP keepalive 是内核层的连接探活机制(默认探测周期长达约 2 小时,判断对端是否还活着);HTTP Keep-Alive 是应用层的连接复用(在同一条 TCP 连接上串行收发多个 HTTP 请求,省去反复握手)——两者解决的是完全不同的问题

参考答案要点
  • 正确答案 D. 一个管「探活」(对端/中间设备是否断开),一个管「复用」(避免每次请求重建 TCP),层次与目的都不同
  • A 完全不同的机制,互相独立配置;B 作用正好互换
  • C 两者互不影响;也正是 TCP keepalive 太慢,长连接健康检查通常用应用层心跳
来源:synthesized

q484 · 中等

关于 ping 与 traceroute(tracert) 的原理,正确的是?
A. ping 走 TCP 80 端口,traceroute 走 UDP 53 端口
B. traceroute 依靠每台路由器主动周期性上报路由表实现
C. 两者都基于 ICMP:ping 发 Echo Request/Reply 测连通性与往返时延;traceroute 发送 TTL 递增的探测包(可用 UDP/ICMP/TCP),每跳路由器把 TTL 减到 0 时丢弃并回送 ICMP Time Exceeded,从而逐跳揭示路径与延迟(ping 根本不涉及端口概念)
D. ICMP 报文不携带源地址,所以 traceroute 无法知道每一跳是谁

参考答案要点
  • 正确答案 C. traceroute 的本质是故意制造 TTL 到期,借路由器回送的 ICMP Time Exceeded(其 IP 源地址即该跳路由器)逐跳探测
  • A ping/traceroute 都不基于 TCP;B 是被动回送,不是路由器主动上报
  • D Time Exceeded 报文的源地址就是路由器地址,这正是能画出每一跳的原因
来源:[cloudflare.com](https://www.cloudflare.com/learning/network-layer/what-is-traceroute/)

q485 · 中等

以太网默认 MTU 1500 字节,TCP 的 MSS 通常取 1460。关于分片与 MSS,正确的是?
A. UDP 也内建了 MSS 协商机制,天然避免 IP 分片
B. MSS = MTU 减去 IP 头(20 字节)与 TCP 头(20 字节);TCP 在握手时协商 MSS 并按路径 MTU 调整,尽量避免 IP 分片——因为 IP 分片只要丢一片,整个数据报作废需要整体重传
C. IP 分片在每一跳路由器上都先重组再转发
D. MSS 比 MTU 大更高效,应尽量设成 2000

参考答案要点
  • 正确答案 B. 1500-20-20=1460;TCP 用 MSS/路径 MTU 发现把分片挡在源端,分片丢一片全重传的代价太高
  • C 重组只发生在最终目的主机;D 超过路径 MTU 的报文会被分片或(置 DF 位时)被丢弃并回 ICMP 需要分片错误
  • A UDP 没有 MSS 概念,超长直接交给 IP 分片(QUIC 在应用层自己解决)
来源:synthesized

q486 · 困难

TCP 三次握手中,服务端发出的 SYN+ACK 报文在中途丢失,接下来会发生什么?
A. 双方各自重传:服务端按自己的策略重传 SYN+ACK(次数由 tcp_synack_retries 控制),客户端等不到 SYN+ACK 也会重传 SYN;抓包会看到 SYN 与 SYN+ACK 交替出现、各自按指数退避
B. 连接立即失败,客户端会收到 RST
C. 只能由客户端重传 SYN,服务端绝不会重传 SYN+ACK
D. 服务端会改用 UDP 重发握手报文

参考答案要点
  • 正确答案 A. 每一端的报文由该端自己的重传定时器负责:服务端重传 SYN+ACK,客户端重传 SYN,超时前连接不会失败
  • B 在重试耗尽前不会 RST 失败;C 服务端有独立的半连接重传队列与次数限制
  • D 握手不会切换协议
来源:synthesized

q487 · 中等

服务器上 netstat 看到数千条 CLOSE_WAIT 状态的连接堆积。最可能的原因与处置是?
A. 本机主动关闭连接过多——CLOSE_WAIT 是 TIME_WAIT 的别称
B. 没开内核参数 net.ipv4.tcp_tw_reuse
C. 这是遭遇对端 RST 攻击的典型表现
D. 对端已发 FIN、内核已回 ACK,但本机应用一直没调用 close()——CLOSE_WAIT 堆积基本指向本服务代码连接泄漏(正常路径/异常路径漏关连接),应先查代码补 close/try-finally,而不是调内核参数

参考答案要点
  • 正确答案 D. CLOSE_WAIT 属于「被动关闭方」:等的是应用层 close(),堆积只能说明程序没关连接
  • A TIME_WAIT 在主动关闭方,两者是完全不同的状态与归属
  • B/C tw_reuse 管 TIME_WAIT 复用,RST 也不会把连接置为 CLOSE_WAIT——调内核参数救不了代码泄漏
来源:synthesized

q488 · 中等

浏览器跨域请求中的 CORS 预检(preflight),下列说法正确的是?
A. 所有跨域请求都会先发一次 OPTIONS 预检
B. 预检由服务端主动发起,询问浏览器是否放行
C. 预检结果不能缓存,每个请求都要重新发一次
D. 「简单请求」(方法为 GET/HEAD/POST,且 Content-Type 限于 application/x-www-form-urlencoded、multipart/form-data、text/plain,无自定义头)不触发预检,直接带 Origin 发出;而 PUT/DELETE、application/json、自定义头(如 X-Token)会先触发 OPTIONS 预检,服务端返回 Access-Control-Allow-* 通过后才发真实请求

参考答案要点
  • 正确答案 D. 预检判定规则:方法、Content-Type、自定义头任一「非简单」即先 OPTIONS;这就是前端常见「接口先收到一个 OPTIONS 请求」的原因
  • A 简单请求不预检,直接发真实请求并附 Origin;B 预检是浏览器自动行为,不是服务端发起
  • C 响应中的 Access-Control-Max-Age 允许浏览器缓存预检结论,期内不再重复 OPTIONS
来源:[developer.mozilla.org](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS)

q489 · 中等

DNS 在传输层协议的选择上,正确的是?
A. DoT/DoH 是把 DNS 改为跑在 UDP 443 端口
B. 常规查询走 UDP 53(小包、低开销);响应超长(如 DNSSEC 大记录超出 UDP 512 字节/EDNS 上限)或被置截断标志时改用 TCP 重查;区域传送(zone transfer,AXFR)必须走 TCP
C. DNS 只使用 UDP,完全不使用 TCP
D. 权威域名服务器只用 TCP,本地递归服务器只用 UDP

参考答案要点
  • 正确答案 B. UDP 查询为主、大响应与 AXFR 走 TCP,是 DNS 协议的标准设计
  • C 忽略了 TCP 回退与区域传送;D 权威/递归角色与协议选择无关
  • A DoT 是 TLS over TCP 853,DoH 是 DNS over HTTPS(TCP 443),都不是 UDP
来源:synthesized

q774 · 中等

关于 Protocol Buffers 的编码格式(wire format)与 JSON 的对比,下列说法错误的是?
A. protobuf 用 varint 编码整数:每个字节只有 7 位是有效数据,最高位作为「后面还有字节」的标志位,因此数值越小占字节越少,150 这样的数只需 2 字节
B. 二进制里用「字段编号+wire type」拼成 tag 代替字段名,缺失字段不占任何字节;报文本身不含字段名与类型,不是自描述格式,解码端必须有 .proto 定义才能还原含义
C. int32 字段传负数时按 64 位补码编码,需要 10 个字节;频繁出现负数的字段应改用 sint32/sint64,它用 ZigZag 变换把负数映射为小无符号数,1~2 字节就能装下
D. protobuf 比 JSON 小的根本原因是序列化时默认启用了 gzip 压缩,把字段名和空白符都压缩掉了

参考答案要点
  • 答案 D,说法错误。protobuf 的小来自线格式设计本身:varint 变长整数、tag 只存字段号不存字段名、没有引号冒号等分隔符、缺省字段零成本、packed repeated 多个值共享一个 tag;与 gzip 无关,想再压缩可以外层 gzip,但那是可选项
  • A 正确:varint 每字节 7 位数据 + 1 位 continuation bit,小数值 1 字节,64 位最大 10 字节
  • B 正确:tag = (field_number << 3) | wire_type;非自描述是双刃剑——省空间,但没有 .proto 就只能看到一串编号和裸数据,这也是抓包调试 gRPC 需要proto文件的原因
  • C 正确:负数补码高位全 1;ZigZag 映射 0→0、-1→1、1→2、-2→3,交错编成小无符号数
来源:[protobuf.dev](https://protobuf.dev/programming-guides/encoding/)

q776 · 中等

关于四层(L4)与七层(L7)负载均衡的区别,下列说法正确的是?
A. 四层负载均衡必须解析完整 HTTP 报文才能完成转发,因此只能做轮询算法
B. 四层 LB 基于 IP+端口转发(NAT/DR 模式),不解析应用层内容,吞吐高、延迟低、开销小,但无法按 URL 路由、无法改写 HTTP 头、无法做基于内容的灰度;七层 LB 解析 HTTP 协议,支持按路径/host 路由、header 改写、SSL 卸载、Cookie 会话保持,代价是更大的解析与缓冲开销
C. 七层负载均衡不能做健康检查,因为健康检查只能工作在四层
D. LVS 是典型的七层负载均衡软件,Nginx/Envoy 是典型的四层负载均衡软件

参考答案要点
  • 答案 B。这是 L4 与 L7 最核心的分工:L4 看连接(IP+port,改 IP/端口/MAC),L7 看请求内容(URL、header、cookie、body)
  • A 错:四层恰恰不解析应用层,所以快,但功能弱;不是只能轮询,ipvsadm 支持 rr/wrr/lc/sh 等调度算法
  • C 错:七层可以做 HTTP 语义健康检查(请求 /healthz 判返回码与 body),比四层 TCP 连通性探测更准;四层只能做 TCP/UDP 探测
  • D 错,说反了:LVS 是四层(NAT/DR/TUN/fullnat);Nginx/Envoy 以七层为主,同时也能做四层 stream 透传
来源:synthesized

q778 · 中等

关于正向代理与反向代理,下列说法正确的是?
A. 两者没有本质区别,只是部署位置不同,可以随意互换叫法
B. 正向代理代理的是客户端:客户端流量先交给代理出去,服务端看到的是代理 IP(典型如公司出口代理、科学上网);反向代理代理的是服务端:客户端直接访问的就是代理,真实后端被隐藏(Nginx 反代、CDN 边缘节点)。正向代理常用 HTTP CONNECT 建立隧道透传 HTTPS,反向代理常做 TLS 终止、缓存、限流与改写
C. 反向代理是为客户端服务的,所以它的访问日志里不包含任何后端服务器信息
D. X-Forwarded-For 是攻击者专用的伪造头,HTTP 规范明确禁止代理使用

参考答案要点
  • 答案 B。判别标准就一条:代理站在谁那边、隐藏谁。正向代理隐藏客户端,反向代理隐藏服务端
  • A 错:两者角色、部署位置、用途都不同,不能混叫
  • C 错:反代日志恰恰要记录 upstream 信息,如 Nginx 的 $upstream_addr/$upstream_response_time/$upstream_status,是排障 502/504 的关键数据
  • D 错:XFF 是事实标准的传递头,链路上每经过一个受信代理就追加一跳真实 IP;风险在于客户端可以伪造首段,只有「最后一个受信代理」追加/重写的部分才可信,生产上常配合 set_real_ip_from 白名单或 PROXY protocol 使用
来源:synthesized

q780 · 中等

服务端要向浏览器持续推送订单状态变化,客户端几乎不需要向服务端发消息。关于长轮询、SSE、WebSocket 三者的选型,下列说法正确的是?
A. 必须用 WebSocket,因为 SSE 和长轮询在技术上不可能实现服务端向客户端推送
B. SSE(Server-Sent Events)基于 HTTP、天然单向(server→client),EventSource 自带断线自动重连并携带 Last-Event-ID 续传;但 HTTP/1.1 下浏览器对同一域名只有约 6 个连接的硬限制(所有标签页共享),且原生 EventSource 只能发 GET、不能带自定义请求头;本场景客户端极少上行,SSE 配合普通 POST 接口上报即可,是比 WebSocket 更轻的选型,HTTP/2 多路复用可缓解连接数限制
C. 长轮询最省服务器资源,因为请求挂着不返回就不算连接
D. SSE 与 WebSocket 的报文格式完全相同,都是二进制帧

参考答案要点
  • 答案 B。单向推送+极少上行的场景,SSE 的自动重连、Last-Event-ID 断点续传、纯 HTTP 基础设施友好(经过代理/网关无需特殊配置)都是优势;需要上行时用普通 fetch/POST 补一条通道即可
  • A 错:SSE 本身就是服务端推送技术;长轮询靠服务端 hold 住请求也能做到准实时,只是开销大
  • C 错:每个挂起的长轮询请求都占用一条连接和服务器并发线程/事件槽,大量客户端下最耗资源,且每次推送后要重建请求(延迟与额外开销)
  • D 错:SSE 是 text/event-stream 纯文本格式(event/data/id 行);WebSocket 是独立帧协议,支持文本帧与二进制帧
  • 补充分辨点:WebSocket 需要双向、低延迟、二进制协议或自定义子协议时才值得上;注意反向代理对 SSE 要关闭响应缓冲(proxy_buffering off 或 X-Accel-Buffering: no),否则事件被攒着批量吐出
来源:[developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)

q782 · 中等

高流量场景下网络收包路径的硬中断、NAPI、软中断与多队列网卡,下列说法正确的是?
A. 网卡每收到一个包就触发一次硬中断,内核在硬中断上下文里完整执行协议栈解析并把数据递交给应用,因此中断占比高是正常现象
B. 高流量下采用 NAPI 机制:硬中断只做最少的工作(登记一次),随后驱动以轮询方式批量收包,协议栈处理放在软中断(NET_RX softirq)上下文;多队列网卡(RSS)把流量哈希到不同队列,配合中断亲和性(irqbalance 或手工 smp_affinity)把各队列中断绑到不同 CPU,避免单核 si 飙高
C. top 里的 %si 高说明磁盘 IO 繁忙,应优先去看 iostat
D. RPS/RFS 是网卡硬件功能,单队列网卡无法模拟多队列分流

参考答案要点
  • 答案 B。中断风暴问题靠「中断+轮询」混合的 NAPI 解决;软中断集中在各 CPU 的 softirq 时间与 ksoftirqd 线程里处理 NET_RX/NET_TX,这是 top 里 %si 的主要来源
  • A 错:每包一中断在高 PPS 下会活活把 CPU 打死(中断风暴),这正是 NAPI 要解决的;硬中断上下文也不能做耗时处理
  • C 错:%si 是 softirq,大头是网络收发;判断软中断丢包看 /proc/net/softnet_stat 第二列(processed/dropped)与 ethtool -S 的 rx_dropped,磁盘 IO 应看 %wa 与 iostat
  • D 错:RPS/RFS 是内核纯软件机制,把收包处理抛到别的 CPU、按流保持 CPU 亲和,单队列网卡照样能用;另外 netdev_max_backlog 满了会在软中断入口丢包,机器高 PPS 下可调大
来源:synthesized

q783 · 中等

关于 NAT/NAPT 与「外网不能主动访问内网」,下列说法正确的是?
A. NAT 只转换 IP 地址,从不修改端口
B. NAPT(网络地址端口转换)靠内核连接跟踪表(conntrack)把内网连接的 (源IP:端口) 映射为出口公网 (IP:端口);外网主动发来的包在表中查不到对应映射与期望方向,被直接丢弃——这就是「外网不能主动访问内网」的原因;UDP 打洞(P2P)借 STUN 服务器让双方各自与公网中介建好映射,再互发包在各自 NAT 上「戳出」双向通路,失败时退化为 TURN 中继转发
C. conntrack 表满了不影响新建连接,内核会自动无限制扩容
D. NAT 设备修改了 IP 和端口之后,不需要重算传输层校验和

参考答案要点
  • 答案 B。家用/云上出网基本都是 NAPT;conntrack 是状态化 NAT 的基石,每条 TCP/UDP 会话占一条表项,双向包按表匹配放行并还原地址
  • A 错:多对一复用必须改端口才能区分内网不同主机与连接
  • C 错:conntrack 表有上限,打满后新连接被丢弃(日志 nf_conntrack: table full, dropping packet),高并发短连接(压测机)或 P2P 场景常见,需调 nf_conntrack_max 与超时参数
  • D 错:IP 与端口变了,TCP/UDP 校验和(伪头部参与计算)必须重算/增量更新,否则对端直接丢包
  • 延伸:打洞成功与否取决于 NAT 类型(完全锥形容易、对称型难);WebRTC 的 ICE 就是 STUN/TURN 的工程化组合
来源:synthesized

q785 · 中等

关于 Linux 拥塞控制算法 CUBIC 与 BBR,下列说法正确的是?
A. CUBIC 把任何一次丢包都视为拥塞,只要丢一个包就会把拥塞窗口立刻降回 1 MSS 从头慢启动
B. BBR 主要依据丢包率调节窗口,丢包越多发得越猛,以此抢占带宽
C. BBR 通过主动估计链路的瓶颈带宽(Bottleneck Bandwidth)与最小往返时延(RTT),按带宽时延积(BDP)调节发送速率,不依赖丢包作为拥塞信号;在有一定随机丢包或深缓冲(bufferbloat)的链路上,常能比 CUBIC 取得更高吞吐与更低排队延迟
D. 开启 BBR 后内核会自动清空 qdisc 队列,报文从此永不排队

参考答案要点
  • 答案 C。BBR 建模「该链路最多能发多快」而不是「等到丢包再退让」,对无线随机丢包链路和高延迟长肥管道收益明显;google/quiche 与很多跨国传输场景默认启用
  • A 错:只有 RTO 超时才把窗口打回 1 MSS 并把 ssthresh 设为当时一半;三次重复 ACK 触发的快速重传/快速恢复只是乘性减小(窗口减半),不是每次丢包都从头慢启动
  • B 说反了:BBR 恰恰不依赖丢包率;「抢带宽」的印象来自 BBRv1 对基于丢包算法的竞争性,但不是靠丢包调窗
  • D 错:BBR 不清空 qdisc,只是主动控制 inflight 数据量接近 BDP 来避免灌满缓冲;队列规则与缓冲仍由 tc/qdisc 管理
  • 实用补充:内核通过 net.ipv4.tcp_congestion_control 切换,sysctl net.ipv4.tcp_available_congestion_control 查看可用算法
来源:synthesized

q788 · 中等

关于 TLS 1.3 的 0-RTT 早数据(early data),下列说法正确的是?
A. 0-RTT 数据由 TLS 层加密并默认防重放,因此可以安全用于任何请求,包括下单和支付
B. 0-RTT 基于会话恢复(PSK/resumption):客户端在第一个 ClientHello 里就能携带应用数据,省掉一个 RTT;但 0-RTT 数据不保证防重放,攻击者原样重发捕获的 0-RTT 报文就可能重复执行操作,所以非幂等请求(下单、支付、改密码、发帖)不应接受走 0-RTT,服务端还应配合一次性会话票据、限流与重放窗口防护
C. 0-RTT 是 HTTP/2 的流控特性,和 TLS 版本无关
D. 只要站点开启 HSTS,浏览器就会自动获得 0-RTT 防重放能力

参考答案要点
  • 答案 B。0-RTT 是性能优化,重放是它的原罪;协议设计者的立场就是:0-RTT 只用于幂等/安全可重放的请求,或应用层自带防重放(如带唯一 ID 且服务端去重)
  • A 错:加密≠防重放,攻击者不需要解密,原样重发即可
  • C 错:0-RTT 是 TLS 1.3 会话恢复机制,与 HTTP 版本无关
  • D 错:HSTS 是「强制 HTTPS+防降级」的响应头,与 0-RTT 重放防护毫无关系
  • 工程备注:反代(如 Nginx ssl_early_data on)开启时要同步在应用侧识别 Early-Data 头并谨慎处理非幂等请求
来源:synthesized

q789 · 中等

关于限流与过载场景下 HTTP 状态码的正确语义与客户端行为,下列说法正确的是?
A. 429 Too Many Requests 表示客户端请求频率超限,规范建议服务端携带 Retry-After 头说明何时可重试;503 Service Unavailable 表示服务端暂时过载/维护,同样建议带 Retry-After;客户端正确姿势是按 Retry-After 或指数退避加抖动重试,并配合熔断,而不是立刻原样重发
B. 408 是服务端限流专用状态码,含义是「服务端不想处理这个请求」
C. 客户端收到 429 后应立即无间隔重发原请求,直到成功为止
D. 502、503、504 含义相同,网关实现里可以随意互换使用

参考答案要点
  • 答案 A。Retry-After 可给秒数或 HTTP-date;大规模系统里还常用响应头/错误体携带更细的退避指引,客户端务必加抖动(jitter)防止同步重试形成重试风暴
  • B 错:408 Request Timeout 是「客户端发出请求后,服务端在等待请求体/完成请求时超时」,与限流无关
  • C 错:立即重试会火上浇油,把过载服务彻底压垮,这正是重试风暴的成因
  • D 错:502 Bad Gateway 是上游返回无效响应/连接被拒;503 是本端或上游过载/停机维护;504 Gateway Timeout 是等上游超时;语义不同,监控告警与客户端处理策略也应不同
来源:synthesized

q792 · 简单

关于 ARP 协议的工作原理,下列说法正确的是?
A. 同网段主机 A 给 B 发 IP 包前先查本地 ARP 缓存,未命中则广播 ARP 请求(目的 MAC 为全 F),B 以单播应答自己的 MAC;免费 ARP(gratuitous ARP)在主机配置 IP 或 VRRP 主备切换时主动广播,用于宣告地址占有与检测 IP 冲突
B. ARP 请求是单播发送的,ARP 应答才是广播,与 A 的描述相反
C. 跨网段通信时,源主机会把 IP 头里的目的地址直接改写为网关 IP,以太网帧目的 MAC 保持不变
D. ARP 欺骗在内网不可能成功,因为交换机硬件会校验 ARP 报文的合法性

参考答案要点
  • 答案 A。请求广播、应答单播是 ARP 的基本行为;免费 ARP 是故障切换(VRRP/keepalived)后刷新邻居表的关键
  • B 把方向说反了
  • C 错:跨网段时 IP 头的目的地址始终是最终目标,变的是以太网帧的目的 MAC——填默认网关的 MAC;「IP 端到端不变,链路层逐跳替换」是理解路由的核心
  • D 错:ARP 本身无任何认证,同一广播域内任何人都能应答伪造映射实施中间人(ARP 欺骗/毒化),缓解手段是动态 ARP 检查(DAI)、端口安全、静态绑定;这也是内网纵深防御的一环
来源:synthesized

简答题(26)

q165 · 中等

TCP 建立连接为什么是三次握手而不是两次?请说明三次握手每一步的报文和状态变化,并解释两次握手会带来什么问题。

参考答案要点
  • 流程:客户端发 SYN(seq=x)进入 SYN_SENT;服务端回 SYN+ACK(seq=y,ack=x+1)进入 SYN_RCVD;客户端回 ACK(ack=y+1),双方进入 ESTABLISHED
  • 原因一:防止已失效的历史连接请求报文突然又到达服务端,两次握手会让服务端建立无效连接白白浪费资源
  • 原因二:三次是确认双方收发能力的最小次数,两次握手时服务端无法确认客户端能收到自己的报文
  • 双方各自完成初始序列号(ISN)的同步与确认,ISN 随机化防止历史报文序号混淆和安全攻击
  • 加分点:SYN 洪泛攻击原理与 SYN Cookie 应对
来源:[javabetter.cn](https://javabetter.cn/sidebar/sanfene/network.html)

q166 · 中等

请简述 TCP 拥塞控制机制,说明慢启动、拥塞避免、快速重传、快速恢复分别在什么条件下触发、做了什么。

参考答案要点
  • 慢启动:cwnd 从小值起步按每 RTT 翻倍指数增长,直到达到阈值 ssthresh
  • 拥塞避免:cwnd 超过 ssthresh 后改为每 RTT 线性加 1(加性增大)
  • 快速重传:连续收到 3 个重复 ACK 立即重传丢失报文,不必等重传超时
  • 快速恢复:快重传触发后 ssthresh 减半、cwnd 设为新 ssthresh 继续拥塞避免;若是超时拥塞则 cwnd 重置为 1 重新慢启动
  • 能区分拥塞控制(应对网络全局拥塞)与流量控制(接收方窗口 rwnd)
来源:[javabetter.cn](https://javabetter.cn/sidebar/sanfene/network.html)

q167 · 中等

HTTP/1.1、HTTP/2、HTTP/3 分别解决了什么问题?请说明每个版本的关键改进和遗留问题。

参考答案要点
  • HTTP/1.1:默认长连接 keep-alive 复用 TCP 连接、支持管道化但存在 HTTP 层队头阻塞、增加缓存控制和断点续传
  • HTTP/2:二进制分帧、多路复用解决 HTTP 层队头阻塞、HPACK 头部压缩、服务器推送
  • HTTP/2 遗留问题:TCP 层队头阻塞,一个包丢失会阻塞所有流
  • HTTP/3:基于 QUIC(UDP),流间相互独立解决 TCP 队头阻塞、0/1-RTT 建连、连接迁移
  • 能说出演进动机:每个版本都是在解决上一代的性能瓶颈
来源:[javaguide.cn](https://javaguide.cn/cs-basics/network/other-network-questions.html)

q343 · 中等

TCP 的流量控制和拥塞控制都在限制发送速率,两者有什么区别?请说明滑动窗口如何实现流量控制、接收方通告窗口为 0 时发送方会一直干等吗,以及拥塞窗口 cwnd、接收窗口 rwnd 与实际发送窗口三者的关系。

参考答案要点
  • 流量控制是端到端问题:防止发送方发太快淹没接收方缓冲区;拥塞控制是全局问题:防止把网络打爆,两者独立运行
  • 实际发送窗口 = min(cwnd, rwnd):拥塞窗口按慢启动/拥塞避免增长,接收窗口由对端通过 TCP 头部窗口字段通告
  • 滑动窗口:发送方已发送未确认的数据量不能超过通告窗口,可流水线发送不必一问一答
  • 接收窗口为 0 时发送方启动持续计时器,周期发窗口探测报文(指数退避),防止双方互相等待死锁
  • 追问方向:糊涂窗口综合征(一次只通告几个字节),Nagle 算法与接收方延迟通告如何配合
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_feature.html)

q344 · 困难

线上服务器 netstat 统计出几万个 TIME_WAIT(都是本机主动发起的短连接)。TIME_WAIT 为什么要等 2MSL 而不是立刻释放?TIME_WAIT 过多有什么实际危害?请给出治理方案,并解释 tcp_tw_reuse 为什么能用、tcp_tw_recycle 为什么被 Linux 移除。

参考答案要点
  • 等 2MSL 的两个理由:最后一个 ACK 若丢失,可等对方重传 FIN 并再回 ACK;让旧连接的重复报文在网络中自然消亡,避免污染四元组相同的新连接
  • 危害:每条 TIME_WAIT 占内核 socket 内存,更致命的是客户端侧端口耗尽导致无法建立新连接
  • 治理:开 tcp_tw_reuse(仅对主动发起方生效,依赖时间戳更安全);客户端改长连接/连接池减少主动关闭
  • tcp_tw_recycle 在 NAT 环境下因同源不同主机时钟偏差被 PAWS 判为旧报文误杀连接,Linux 4.12 起移除
  • 根因方案:让被动方主动关闭,把 TIME_WAIT 留在对端;SO_REUSEADDR 只解决服务重启 bind 失败,不减少 TIME_WAIT
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_tw_reuse_close.html)

q346 · 中等

TCP 是面向字节流的协议,应用层两次写入的消息可能被对端一次读出(粘包),或一条消息被拆成多次读到(拆包)。请解释粘包拆包产生的根本原因,列出应用层常用的四种解决方案,并回答 UDP 会不会粘包、为什么。

参考答案要点
  • 根因:TCP 把应用数据视为无边界的字节流,Nagle 算法合并小包、发送缓冲区与 MSS 分段、接收方读取时机,都会造成消息边界错位——本质是应用层没有定义消息边界,不是 TCP 的 bug
  • 方案一:固定长度消息,不足补齐;实现最简单但浪费带宽
  • 方案二:特殊分隔符,如 HTTP 的 CRLF、Redis RESP 的 \r\n;内容里出现分隔符需转义
  • 方案三:长度字段前缀(定长 header + body),最通用,Netty 的 LengthFieldBasedFrameDecoder 即此
  • 方案四:应用层协议自带结构(由 parser 判界),底层仍依赖前三种;UDP 面向报文保留消息边界,一次 sendto 对应一次 recvfrom,不粘包,但可能整包丢失或乱序
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_stream.html)

q347 · 困难

以 TLS1.2 + ECDHE 套件为例,描述 HTTPS 从 TCP 建连后到应用数据加密传输的完整握手过程;客户端是如何校验证书链的;TLS1.3 的握手为什么只需 1-RTT、会话恢复时又如何做到 0-RTT,0-RTT 有什么风险。

参考答案要点
  • TLS1.2 ECDHE 关键四步:ClientHello(随机数+套件列表)→ ServerHello+证书+ServerKeyExchange(ECDHE 公钥参数,用证书私钥签名)→ ClientKeyExchange(客户端 ECDHE 公钥)→ ChangeCipherSpec+Finished;双方由两个随机数+预主密钥推导会话密钥
  • 证书链验证:从站点证书沿 issuer 逐级验签直到系统内置根 CA;校验域名匹配(SAN)、有效期、吊销(CRL/OCSP);服务器用私钥对密钥交换参数签名,中间人没有私钥无法伪造
  • TLS1.3 1-RTT:ClientHello 直接带 key_share,ServerHello 即可确定会话密钥,之后的握手消息全部加密,比 1.2 少一次往返
  • 会话恢复:TLS1.2 Session ID/Ticket 需 1-RTT;TLS1.3 用 PSK + early_data 实现 0-RTT,第一个 RTT 就携带应用数据
  • 0-RTT 风险:数据是重放的,只能携带幂等请求(GET);追问:RSA 密钥交换为何被 1.3 废弃(不具备前向安全)
来源:[xiaolincoding.com](https://xiaolincoding.com/network/2_http/https_ecdhe.html)

q348 · 困难

HTTP/2 相比 HTTP/1.1 的核心改进是什么?请解释多路复用的工作原理(帧、Stream、HPACK 头部压缩),并说明 HTTP/2 的队头阻塞发生在哪一层、为什么存在、为什么在 HTTP/2 内部无法根治,最终是如何被 HTTP/3 解决的。

参考答案要点
  • 核心改进:二进制分帧层把报文拆成帧、单条 TCP 连接上多个 Stream 并行交错传输、HPACK 头部压缩(静态表+动态表+哈夫曼编码)、服务器推送
  • 多路复用:每个请求/响应是一个 Stream,消息由多个 Frame 组成,不同 Stream 的帧可交错发送,接收端按 Stream ID 重组——彻底解决 HTTP/1.1 管线化与多开连接的问题
  • 队头阻塞在 TCP 层:所有 Stream 跑在同一条 TCP 上,任何一个报文丢失,内核必须按序交付,后面所有 Stream 的数据都得等重传完成
  • HTTP/2 无法根治:TCP 的顺序交付语义在内核,应用层协议改不了;丢包率 2% 时 HTTP/2 可能比 1.1 多连接更差
  • HTTP/3 换 QUIC:传输层以 Stream 为独立交付单位,丢包只阻塞所在 Stream;追问:Stream 优先级与按 Stream 的流量控制
来源:[xiaolincoding.com](https://xiaolincoding.com/network/2_http/http2.html)

q350 · 中等

WebSocket 是怎么从一条 HTTP 连接升级为全双工长连接的?请写出握手请求/响应的关键头部与状态码、Sec-WebSocket-Accept 的计算方法;升级完成后这条连接上还能收到普通 HTTP 响应吗,帧类型如何区分,客户端发送的数据帧为什么要加掩码?

参考答案要点
  • 握手:客户端发 GET 请求,带 Upgrade: websocket、Connection: Upgrade、Sec-WebSocket-Key(16 字节随机数的 base64);服务端返回 101 Switching Protocols,带 Sec-WebSocket-Accept
  • Accept = base64(SHA-1(Key + 固定 GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11)),客户端校验通过才算升级成功,防止普通 HTTP 服务器误应答
  • 升级后该 TCP 连接不再有 HTTP 语义,全部是 WebSocket 帧,由帧头 opcode 区分:0x1 文本、0x2 二进制、0x8 关闭、0x9 ping、0xA pong
  • 客户端→服务端帧必须掩码(4 字节掩码键与载荷异或),防止中间代理缓存污染攻击;服务端帧不掩码
  • 心跳与断线:周期 ping/pong 探活并维持 NAT 映射,超时未回包主动关闭重连;握手也可带 Sec-WebSocket-Protocol 协商子协议
来源:[xiaolincoding.com](https://xiaolincoding.com/network/2_http/http_websocket.html)

q351 · 中等

维护服务间 TCP 长连接时,为什么通常不用 TCP 自带的 keepalive,而是在应用层设计心跳(如每 30 秒一次 ping/pong)?请对比 TCP keepalive 与应用层心跳,说明心跳间隔如何权衡,以及 TCP 的 Keep-Alive 和 HTTP 的 Keep-Alive 是不是一回事。

参考答案要点
  • TCP keepalive 默认 7200s 无数据才探测、间隔 75s 共 9 次,周期太长无法及时感知死链;且只证明 TCP 可达,不能证明对端应用进程健康(进程死锁时内核照样回 ACK)
  • 应用层心跳可感知应用层健康度、间隔可调,还能顺带承载业务信息(负载、配置版本);心跳同时防止 NAT/防火墙空闲表项过期导致静默断链
  • 间隔权衡:太短费带宽与功耗(移动端敏感),太长发现死链慢且易被 NAT 超时(常见 NAT 超时 1~5 分钟),一般 30~60s,移动端 IM 常做智能心跳
  • 判死策略:连续 N 个周期未回心跳判死,断开重连配指数退避;重连风暴要加随机抖动
  • TCP Keep-Alive 是传输层探活机制;HTTP Keep-Alive 是复用同一条 TCP 发多个 HTTP 请求,两者名字像但完全是两回事
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_http_keepalive.html)

q352 · 中等

请完整描述浏览器解析一个域名时的 DNS 解析全链路:各级缓存与查询顺序、递归查询和迭代查询的区别、拿到 A 记录前还可能发生什么(CNAME 链、CDN 调度、负载均衡),以及 DNS 为什么主要用 UDP、什么情况下会用 TCP。

参考答案要点
  • 顺序:浏览器 DNS 缓存 → 操作系统缓存与 hosts → 本地域名服务器 LDNS(通常运营商)→ 根域名服务器 → 顶级域名服务器(.com)→ 权威域名服务器
  • 递归 vs 迭代:客户端对 LDNS 是递归(要求最终答案),LDNS 对根/顶级/权威是迭代(逐级问下一跳在哪),最后缓存并按 TTL 返回
  • CNAME 链:接入 CDN 的域名先 CNAME 到服务商调度域名,继续解析才得到 A 记录;DNS 可做多 A 记录轮询负载均衡与就近调度
  • UDP 53:查询报文小、一问一答追求低延迟;响应超过 512B(DNSSEC 等)置截断标志后改 TCP 重查;区域传送 zone transfer 始终用 TCP
  • 安全延伸:DNS 劫持/污染的表现,HTTPDNS、DoH/DoT 的应对思路
来源:[xiaolincoding.com](https://www.xiaolincoding.com/network/1_base/what_happen_url.html)

q353 · 中等

用户访问一个接入了 CDN 的静态资源域名,请描述从 DNS 解析到拿到文件的完整链路(CNAME 接入、GSLB 调度、边缘节点、回源),说明缓存命中/未命中/回源分别指什么,CDN 节点按什么规则决定缓存过期,源站更新后如何让边缘生效。

参考答案要点
  • 接入:源站域名 CNAME 到 CDN 调度域名;LDNS 解析调度域名时,GSLB 根据 LDNS 出口 IP 归属、节点负载与健康度返回一个就近边缘节点 IP
  • 命中:边缘节点本地有该资源(常以 Host+Path 为缓存 key),直接返回,响应头常带 X-Cache: HIT,延迟最低
  • 未命中 MISS:边缘向上层节点或源站回源拉取,写入本地缓存(按响应 Cache-Control/max-age 的 TTL)再返回客户端
  • 过期与刷新:边缘按 TTL 到期后回源校验;源站更新后可向 CDN 下发刷新(purge)清缓存;带随机 query 或鉴权的动态内容不可缓存,走动态加速(链路优化)
  • 追问:回源风暴(热点 key 失效瞬间打穿源站)、缓存 key 设计是否忽略无害 query 参数、负缓存
来源:[javaguide.cn](https://javaguide.cn/cs-basics/network/other-network-questions2.html)

q354 · 中等

Cookie+Session、不透明 Token(服务端存 Redis 校验)和 JWT 三种认证方案的原理与优缺点分别是什么?JWT 的三段结构是什么、签名怎么算、为什么已签发的 JWT 无法在服务端主动失效,工程上有哪些缓解手段?

参考答案要点
  • Cookie+Session:登录后服务端存会话,浏览器存 sessionid Cookie;可随时踢人,但分布式需共享 session(Redis)或粘性路由,每请求一次会话查询
  • 不透明 Token:发随机串,请求时查 Redis 校验,服务端可控可吊销,代价是每次多一跳网络
  • JWT = base64url(header).base64url(payload).signature;签名用 header.alg(HMAC-SHA256 或 RS256)对前两段计算,服务端验签即可信任,免存储、跨服务传递方便
  • JWT 缺点:有效期内无法撤销、体积比 sessionid 大、payload 仅 base64 可被解码,不能放敏感信息
  • 缓解失效:短过期 + Refresh Token 换发、维护黑名单(退化为有状态)、签发时带 token_version/uid 版本号,改号即全部失效
来源:[xiaolincoding.com](https://xiaolincoding.com/network/2_http/http_interview.html)

q355 · 中等

什么是单点登录(SSO)?以 CAS 流程为例,描述用户首次访问 a.com 受保护页面到完成认证的完整跳转过程(ticket 如何传递与校验),说明同父域多系统为何共享 Cookie 即可、跨域系统为什么必须引入认证中心,以及 OAuth2/OIDC 与 SSO 的关系。

参考答案要点
  • SSO:一次登录多系统互通;认证中心统一持有会话,业务系统只认中心签发的一次性凭据
  • CAS 流程:访问 a.com 未登录 → 302 跳认证中心(带 service 回调地址)→ 用户登录,中心写 TGC Cookie → 302 回 a.com?ticket=ST → a.com 服务端拿 ticket 到中心校验换用户信息 → a.com 写本地会话;再访问 b.com 时中心 TGC 仍有效,免登录直接发票
  • 同父域:把 Cookie domain 设为父域(.example.com),子系统天然共享,无需跳转
  • 跨域 Cookie 互不可见,必须靠认证中心 + ticket 转移(或 token 经 URL/postMessage 传递)
  • OAuth2 是授权协议(授权码模式),拿 access_token 访问资源;用它做登录需配 OIDC(id_token 表达身份);CAS 是经典认证协议,职责不同
来源:[javaguide.cn](https://javaguide.cn/system-design/security/basis-of-authority-certification.html)

q357 · 困难

TCP 如何实现可靠重传?请说明:超时重传的 RTO 是如何自适应确定的、超时后重传间隔如何变化;为什么收到 3 个重复 ACK 就可以不等 RTO 立即重传(快速重传);SACK 选择性确认又解决了什么问题。

参考答案要点
  • RTO 自适应:基于加权移动平均的平滑 RTT(SRTT)与偏差(RTTVAR),RTO ≈ SRTT + 4×RTTVAR,动态跟随网络抖动,避免过小误重传/过大恢复慢
  • 超时退避:每次超时 RTO 翻倍,连续超时达上限(tcp_retries2 默认 15 次)后放弃连接;超时同时触发拥塞窗口重置回慢启动
  • 快速重传:接收端缺包后对后续到达的报文重复回 ACK,发送端累计 3 个重复 ACK 即判定该段丢失立即重传,不必等 RTO;配合快速恢复 cwnd 减半进入拥塞避免,吞吐远好于超时重传
  • 为什么是 3 个而不是 1 个:轻度乱序也会产生重复 ACK,取 3 是容忍乱序与确认丢失的折中
  • SACK:接收方在 TCP 选项里报告已收到的离散区间,发送方只补传真正缺失的段,避免 Go-Back-N 式整窗重传
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_feature.html)

q358 · 困难

TCP 的半连接队列(SYN 队列)和全连接队列(accept 队列)分别存放什么、与三次握手的对应关系是什么?如何观察全连接队列溢出?SYN 攻击打的是哪个队列,tcp_syncookies 如何防御?

参考答案要点
  • 收到 SYN → 连接进半连接队列(SYN_RCV);收到第三次握手 ACK → 移入全连接队列(ESTABLISHED)等应用 accept 取走;第三次握手完成不依赖 accept 被调用
  • 全连接队列长度 = min(应用层 backlog, somaxconn);溢出行为由 tcp_abort_on_overflow 决定:0 丢弃 ACK(客户端视角连上了但发数据无响应),1 直接回 RST
  • 观察:ss -lnt 的 Recv-Q(监听 socket 上为当前全队列积压)、netstat -s 中 listen queue/synto listent dropped 计数、/proc/net/netstat 的 ListenOverflows/ListenDrops
  • SYN 攻击:伪造源地址发大量 SYN 半开连接占满半连接队列,正常用户的 SYN 被丢弃
  • tcp_syncookies:队列满时不存半连接状态,把信息编码进 SYN+ACK 的初始序列号,收到合法 ACK 再反算校验直接建连;代价是丢失部分 TCP 选项,再配合调大 tcp_max_syn_backlog、减少重试次数
来源:[xiaolincoding.com](https://xiaolincoding.com/network/3_tcp/tcp_queue.html)

q359 · 中等

HTTP 缓存分为强缓存和协商缓存。两类各自的判定头是什么,命中后浏览器表现差异(200 from cache 与 304)是什么?ETag 相比 Last-Modified 解决了什么问题?no-cache 和 no-store 的区别是什么?

参考答案要点
  • 强缓存:Expires(1.0 绝对时间,受本地时钟影响)与 Cache-Control: max-age(相对秒,优先级更高);命中不发请求,DevTools 显示 200 (from memory/disk cache)
  • 协商缓存:Last-Modified/If-Modified-Since(秒级精度)与 ETag/If-None-Match(内容指纹);命中返回 304 无 body,只需一次头往返
  • ETag 优势:秒内多次修改可感知;mtime 变化但内容未变时免重传;分布式部署注意多机 ETag 一致性否则缓存抖动
  • no-cache = 可以缓存但每次使用前必须协商校验;no-store = 任何地方不存储;另有 public/private、must-revalidate 组合
  • 行为差异:普通刷新会带协商请求,F5/Ctrl+F5 强制 no-cache 全量重拉;这是前端发版后偶发白屏/旧资源的排查点
来源:[xiaolincoding.com](https://xiaolincoding.com/network/2_http/http_interview.html)

q360 · 中等

从浏览器地址栏输入 URL 回车到页面完整展示,中间发生了什么?请按 URL 解析与重定向、DNS 解析、TCP 建连、TLS 握手、HTTP 请求与响应、浏览器渲染的主线串起来讲,并指出每个环节可能被缓存或加速的点。

参考答案要点
  • URL 解析与 HSTS 强制 https、可能的 301 跳转 → DNS 多级缓存解析(浏览器/OS/LDNS)→ TCP 三次握手(可能复用已有 keep-alive 连接)→ TLS 握手(1.3 一轮往返、会话恢复 0-RTT)
  • HTTP 请求:强缓存命中则不发请求;否则发条件请求(协商缓存)或普通请求,携带 Cookie、Accept-Encoding 等
  • 服务端:LB → 网关/应用服务 → 可能查 Redis/DB/下游 RPC → 返回 304/200/重定向;大流量下 CDN 边缘命中
  • 渲染:解析 HTML 建 DOM,遇 CSS 建 CSSOM,遇 JS 默认阻塞解析(async/defer 的差异),DOM+CSSOM 合成渲染树 → 布局 layout → 绘制 paint → 合成 composite;图片等子资源并行加载
  • 加分点:能把缓存、CDN、keep-alive、TLS、重排重绘准确插进主干流程;追问首屏优化(LCP/FCP 指标)
来源:[javaguide.cn](https://javaguide.cn/cs-basics/network/the-whole-process-of-accessing-web-pages.html)

q775 · 中等

gRPC 有哪四种通信模式(streaming 模式)?每种各举一个典型应用场景,并说明流式 RPC 在超时与重试设计上相比一元调用(unary)要额外注意什么。

参考答案要点
  • unary 一元调用:请求-响应,如查询订单详情,语义与 REST 等价
  • server streaming 服务端流:一次请求持续收消息,如订阅行情/配置推送、大文件分块下发、日志尾随
  • client streaming 客户端流:持续发一次收,如监控指标批量上报、分片上传
  • bidirectional streaming 双向流:两边都可独立收发,如 IM 聊天、实时协同编辑、语音帧传输
  • 注意点:流式调用的 deadline 覆盖整个流的生命周期,长生命周期流要么设足够大的 deadline 并在应用层做 idle 超时/心跳检测,要么拆分;自动重试对流是危险的——已消费一半的流重试会造成重复处理,必须配合幂等或从断点(Last-Event-ID/offset 类标记)恢复;流上还要处理背压与半关闭
来源:[grpc.io](https://grpc.io/docs/)

q777 · 中等

负载均衡有哪些常见算法?各自适合什么场景?另外说明:健康检查的主动探测与被动摘除分别是怎么工作的,新加入的后端为什么要做慢启动?

参考答案要点
  • 轮询/加权轮询:请求依次分发,按机器配置设权重;适合请求处理时长相近的长短连接混合场景
  • 最少连接/加权最少连接:转发给当前活跃连接最少的后端;适合单请求处理时长差异大的场景(否则轮询会让慢节点堆积)
  • 源 IP 哈希:同一来源固定落到同一后端,做会话保持;缺点是节点上下线时映射大规模变化、热点源失衡
  • 一致性哈希:以环状哈希空间+虚拟节点减少节点变动时的映射抖动,常用于缓存路由与有状态分片(具体机制见分布式一致性题)
  • 随机:实现简单,大样本下近似均匀
  • 健康检查:主动探测是 LB 周期性向后端发 TCP 连接或 HTTP 请求判活;被动摘除是转发失败累积(fail_timeout + max_fails)后自动标记不可用,二者通常结合,主动防止流量打到已死节点、被动加快突发故障反应
  • 慢启动:新后端(或刚恢复的)虽然健康但缓存冷、连接池空,立即按全量权重压入会被打挂;恢复期权重从低爬升,逐步放流量
来源:synthesized

q779 · 困难

一个静态资源站接入 CDN 后命中率只有 70%,源站带宽压力仍很大。请系统说明:(1) CDN 侧缓存的有效期如何用 Cache-Control 控制(s-maxage 与 max-age 的分工、常见优先级);(2) 什么是回源、回源风暴,有哪些抑制手段(stale-while-revalidate、合并回源/请求折叠、多级缓存);(3) 主动刷新(purge)与预热和被动 TTL 到期的适用差异;(4) 提升命中率还有哪些工程手段。

参考答案要点
  • 有效期分工:max-age 是浏览器/客户端缓存有效期;s-maxage 专门给共享缓存(CDN)用,覆盖 max-age;CDN 判定优先级通常 s-maxage > max-age > Expires。纯静态资源应对内容做版本化(URL 带哈希)+ 长 s-maxage(如 1 年),发版换 URL 即天然刷新,而不是改文件内容靠短 TTL
  • 回源:边缘节点 miss 后向上层或源站取内容。热门内容过期瞬间大量边缘同时回源就是回源风暴。抑制:stale-while-revalidate 允许过期后先返回旧内容、后台异步刷新;合并回源(请求折叠)让同一节点同一资源的并发 miss 只有一个真正回源、其余等结果;多级缓存 L1 边缘→L2 区域→源站层层收敛回源量
  • 主动 purge 适合内容必须立即全局生效的(违规下架、错误页修正),CDN 开放 API 主动清;预热(prewrite/prefetch)适合大促前把资源提前推到边缘;被动 TTL 适合天然可容忍延迟的版本化静态内容,靠时间自然过期
  • 命中率工程手段:规范化 query 参数(把不影响内容的跟踪参数在 CDN 配置里忽略,否则 ?utm=xxx 每个变体都是独立缓存 key 造成穿透);合理设置 Vary(别 Vary: * 或过多头);小文件合并减少请求数;用命中率报表定位低命中 URL 专项治理
来源:synthesized

q781 · 中等

线上偶发「客户端说请求没到、服务端说没收到」。请给出用 tcpdump + Wireshark 做网络层排障的常用姿势:抓包命令与常用 BPF 过滤、Wireshark 里最常用的几个分析动作(过滤表达式、Follow TCP Stream、专家信息)、以及至少两个能用抓包直接定性的典型故障特征。

参考答案要点
  • 抓包:tcpdump -i any -nn -s 0 'host 10.0.0.5 and tcp port 8080' -w dump.pcap;-i any 抓所有网卡、-nn 禁止域名与端口名反解、-w 写文件交给 Wireshark 分析;临时看明文可用 -A
  • BPF 过滤原语:host/net/port/src/dst、and/or/not、tcp[tcpflags] & tcp-syn != 0 等按位匹配;范围尽量收窄,生产上要限时限量,避免抓出几个 G
  • Wireshark:display filter 语法如 tcp.analysis.retransmission、tcp.analysis.zero_window、tcp.flags.reset==1、http.response.code==500、dns.qry.name contains "xxx";Statistics→IO Graph 看吞吐与重传时间线;Follow TCP Stream 把一次会话双向数据拼成可读流;Expert Information 汇总重传/乱序/零窗口等异常
  • 典型特征一:三次握手成功后服务端立刻回 RST——端口没监听或被防火墙 reject;握手 SYN 发出无 SYN+ACK——中间设备丢包或防火墙 drop 典型特征二:TLS ClientHello 发出后无回应——经典 MTU 黑洞或中间设备丢大包;大量重传与 dup ack——链路质量差或接收缓冲不足;零窗口+window update——对端应用读得太慢被反压
  • 敏感提醒:HTTP 明文抓包会直接看到密码/token,抓包文件要当敏感数据管控
来源:synthesized

q784 · 困难

epoll 已经很好了,为什么内核还要做 io_uring?请说明 io_uring 的核心设计(共享提交/完成队列、批量提交、减少系统调用)、它相比 epoll 的性能收益来自哪里、有哪些典型适用场景,以及为什么很多生产环境至今仍默认不开或限制使用它。

参考答案要点
  • epoll 的固有成本:一次读写至少伴随 epoll_wait + read/write 两次以上系统调用,高频小 IO 时系统调用与上下文切换开销占比高;ET 模式还必须一次读尽、处理 EAGAIN
  • io_uring 核心设计:用户态与内核共享一对环形队列——提交队列 SQ(应用放 IO 请求)与完成队列 CQ(内核放完成结果);请求批量提交、结果异步收割,大部分场景把每次 IO 的系统调用次数降到接近零;SQPOLL 模式甚至由内核线程代为消费 SQ;统一的异步接口覆盖文件读写与网络操作
  • 收益来源:省系统调用与上下文切换、批量摊薄、无锁化的共享内存通信;对高并发代理、存储引擎、数据库这类追求极限 IOPS 的组件收益显著,liburing 大幅简化了编程
  • 适用场景:高 PPS 代理/网关、本地高性能存储、需要统一文件+网络异步 IO 的应用;普通业务 Web 服务用 epoll+线程池已经够,改造成本与收益不成比例
  • 为什么谨慎:io_uring 攻击面大,历史上多次被曝内核提权漏洞(如 2023 年 Google Project Zero 对其安全记录的批评),不少内核/发行版默认限制非特权用户使用(io_uring_disabled/sysctl),容器与托管环境常直接禁用;运维策略上要先评估内核版本与补丁情况
来源:synthesized

q787 · 中等

什么是 DNS 劫持与 DNS 污染?各举一个典型现象,并说明 HTTPDNS、DoH/DoT、EDNS Client Subnet 分别解决什么问题。

参考答案要点
  • DNS 劫持:运营商或中间人在 LocalDNS 上改应答,把域名解析到广告/钓鱼 IP;典型现象:dig 返回的 IP 与权威 DNS 不一致、访问正常网站跳出运营商页面
  • DNS 污染:请求经 UDP 53 明文传输且无认证,中间设备抢先回一个伪造应答(先到先得);典型现象:多渠道解析结果不一致、境外某些域名解析到无效 IP
  • HTTPDNS:客户端绕过运营商 LocalDNS,直接向 HTTP 接口(DNS 服务商)查询解析结果,基于 HTTP/TCP 难以被链路抢答,同时解决运营商调度不准(LocalDNS 出口位置失真导致 CDN 选节点错误),是移动 App 常用方案
  • DoH/DoT:把 DNS 查询跑在加密通道(DNS over HTTPS / over TLS),防窃听与篡改,浏览器与系统级支持越来越广;区别于 HTTPDNS 的私有接口方案,是 IETF 标准协议
  • EDNS Client Subnet:递归服务器把客户端子网信息带给权威 DNS,让 CDN 权威按真实用户位置返回更优节点,改善调度精度
  • 工程兜底:客户端缓存解析结果+多通道(本地 DNS/HTTPDNS)互备,解析失败降级
来源:synthesized

q790 · 中等

请完整描述 OAuth 2.0 授权码模式(Authorization Code Flow)的流程,说明 state 参数和 redirect_uri 白名单分别防什么攻击;为什么移动 App、SPA 这类公共客户端还要加 PKCE?

参考答案要点
  • 授权码流程:用户被客户端引导跳到授权服务器(带 client_id、redirect_uri、scope、state)→ 用户登录并同意授权 → 授权服务器带一次性 code 回调 redirect_uri → 客户端后端用 code+client_secret 换 access_token(可选 refresh_token)→ 用 token 调资源服务器
  • state:客户端生成的随机数,回调时原样带回并校验,防 CSRF(防止攻击者把自己的授权回调塞给受害者会话,把受害者账号绑到攻击者身份)
  • redirect_uri 严格白名单精确匹配:授权码只发往可信地址;不校验或宽松匹配可被 evil-callback 截走 code,也是开放重定向的高危组合点
  • PKCE(Proof Key for Code Exchange):公共客户端拿不出 client_secret,code 可能被同设备其他应用或中间代理截获;客户端先生成 code_verifier,其哈希(S256)作为 code_challenge 传给授权服务器,换 token 时必须出示原 verifier——截获者没有原值,拿到 code 也换不出 token
  • 补充:access token 短效+refresh token 轮换;OpenID Connect = OAuth2 + id_token(认证层),别混用「授权」与「登录认证」语义
来源:synthesized

q791 · 困难

两机房之间 RTT 约 30ms、链路带宽 10Gbps,单条 TCP 流传大文件只跑到约 100 MB/s,但同时开多条流就能跑满。请解释原因(带宽时延积与窗口的关系),说明如何定位与调优(iperf、ss、内核缓冲区参数),以及为什么生产上调大缓冲区要谨慎。

参考答案要点
  • 原因:带宽时延积 BDP = 带宽×RTT = 10Gbps×30ms ≈ 37.5MB,这是「在途未确认数据量」的上限;单条 TCP 流实际窗口取 min(rwnd, cwnd),若窗口上限只有几 MB,发送速率被钉死在 窗口/RTT(如 3MB/30ms≈100MB/s),物理带宽再大也用不满;多条流叠加各自窗口,所以能跑满——这是单流窗口受限的典型指纹
  • 定位:iperf3 -c 对端 -t 30 单流测吞吐,再 -P 8 多流对比;ss -ti dst 对端 看该连接的 cwnd、rcv_space、window scaling;确认 sysctl net.ipv4.tcp_window_scaling=1(默认开)
  • 调优:调大 net.ipv4.tcp_rmem / tcp_wmem 的 max(如 16MB~64MB 量级),内核才能给高 BDP 连接自动增长缓冲;或应用层改并行分块传输(多流/分片)
  • 谨慎点:缓冲区按「连接数×上限」预留内存,数十万连接的服务上调会放大内存占用,引发换页或 OOM;通常是骨干传输机/专线备份场景调大,普通 Web 服务保持默认并依赖连接数扩展
  • 延伸:长肥管道还受丢包率制约(吞吐≈MSS/(RTT×√p) 的 Mathis 公式),高丢包下单纯加窗口无效,BBR 能改善
来源:synthesized

场景题(2)

q773 · 困难

团队内部服务间通信目前全部用 REST+JSON,现在有人提议把订单、库存这类内部高频调用迁到 gRPC,但对外 H5/App 的开放接口维持 REST。请从协议与序列化(HTTP/2 vs HTTP/1.1、protobuf vs JSON)、契约管理(.proto 强类型 vs OpenAPI)、通信模式(四种流)、浏览器与外部兼容性、调试生态五个维度对比 gRPC 与 REST,给出「哪些服务该迁、哪些不该迁」的判断;并重点回答:gRPC 基于 HTTP/2 长连接,为什么会让传统四层负载均衡失衡?有哪些应对方案?

参考答案要点
  • 协议层:gRPC 基于 HTTP/2,多路复用让多条并发调用共享一条 TCP 连接,头部 HPACK 压缩;REST 通常跑 HTTP/1.1 keep-alive,文本 JSON 体积大、编解码慢。内网高频小消息场景 protobuf+HTTP/2 收益明显(报文常小 3~10 倍)
  • 契约:.proto 是强类型契约,代码生成保证双端一致,字段演进有明确规则(增号不重用);OpenAPI 偏描述性文档,约束力弱,容易出现双端字段理解不一致
  • 四种流:unary(普通请求响应)、server streaming(订阅/日志尾随/分块下发)、client streaming(批量上报/分片上传)、bidirectional streaming(实时协同/双向心跳),这是 REST 难以表达的
  • 不该迁的场景:浏览器直连需要 grpc-web 加 Envoy 类代理转换;对外合作方以 REST/OpenAPI 生态为主;gRPC 二进制抓包不可读、调试门槛高;团队语言与运维生态不匹配时迁移成本大于收益
  • LB 失衡问题:四层 LB 按连接分发,而 HTTP/2 把大量并发 stream 挤在少数长连接上,连接建立后所有请求都落在最初选中的后端,负载极不均。应对:L7 gRPC 感知负载均衡(按 stream 而非按连接分发)、client-side LB(客户端经服务发现直连后端自行均衡)、应用层连接池多连接分摊、K8s 下用 headless service + 客户端均衡
来源:[grpc.io](https://grpc.io/docs/)

q786 · 困难

办公网到机房之间新拉了一条 IPSec 隧道,用户反馈:通过隧道 SSH 能正常登录、敲命令也流畅,但 vim 打开大文件会卡死、scp 传文件停滞、部分 HTTPS 页面加载到一半挂起;而走旧链路一切正常。请分析这是什么问题,说明定位方法与处置方案。

参考答案要点
  • 症状定性:小包(SSH 交互、TCP 握手、ClientHello)都通,大数据包过不去——典型的路径 MTU(PMTU)黑洞:IPSec/GRE 等 overlay 封装每包额外增加几十字节头部,路径实际 MTU < 1500;中间防火墙把 ICMP Fragmentation Needed(type 3, code 4)丢弃,发送端的路径 MTU 发现(PMTUD)失效,不知道该分片,大包直接黑洞
  • 为什么 SSH 正常而 scp 卡死:交互流量多是小包(<隧道 MTU),大文件传输/大响应(HTTPS 服务端证书链、大响应体)依赖满尺寸 MSS 段
  • 定位:从一端用 ping -M do -s 1472 逐步减小试探(1472+28=1500;-M do 禁止分片),找出不丢的最大尺寸反推路径 MTU;tcpdump 抓 ICMP type 3 code 4 是否被防火墙吞掉;对比隧道内接口 ip link show 的 mtu 值
  • 处置治本:放行 ICMP Fragmentation Needed(很多安全策略一刀切禁 ICMP 导致此类故障);隧道接口设置正确 MTU
  • 处置缓解:TCP 侧 MSS clamping——iptables ... -j TCPMSS --clamp-mss-to-pmtu 或 ip route 带 advmss,让两端协商出小于路径 MTU 的 MSS;纯 UDP 大包应用需要自己做应用层分片或开启 IP DF 的替代方案
来源:synthesized