输入网址回车后发生了什么:从 DNS 到渲染

副标题 / 摘要 从输入 URL 到页面渲染,涉及 DNS、TCP/TLS、HTTP、渲染管线等多个步骤。本文给出清晰流程与排查思路。 目标读者 想理解浏览器工作流程的开发者 需要排查网络与渲染问题的工程师 前后端协作人员 背景 / 动机 “打开网页很慢”可能源自 DNS、连接、服务器、渲染等任何环节。 理解全链路流程,才能有效定位性能瓶颈。 核心概念 DNS 解析:域名 -> IP TCP/TLS 握手:建立安全连接 HTTP 请求/响应:获取资源 渲染管线:解析 HTML/CSS/JS -> 绘制 实践指南 / 步骤 DNS 解析:缓存/递归解析 TCP/TLS 握手:建立连接 HTTP 请求:请求 HTML 与静态资源 渲染流程:构建 DOM/CSSOM -> Layout -> Paint JS 执行:可能阻塞渲染 可运行示例 用 curl 查看网络层信息: curl -v https://example.com 解释与原理 浏览器加载过程的瓶颈可能发生在“连接层”(DNS/TCP/TLS),也可能在“渲染层”(JS 阻塞、DOM 过大)。 分层分析是定位问题的关键。 常见问题与注意事项 HTTPS 比 HTTP 慢吗? 会多一次 TLS 握手,但可通过复用与缓存降低。 为什么首屏慢? 可能是渲染阻塞或资源过大。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

如何在不可靠协议上构建可靠通信:重传、确认与顺序

副标题 / 摘要 不可靠协议上构建可靠通信的核心是:确认、超时、重传与顺序控制。本文给出工程要点与简化实现示例。 目标读者 需要理解可靠传输机制的后端工程师 设计自定义协议的开发者 对网络底层原理有兴趣的同学 背景 / 动机 UDP 等不可靠协议不保证送达、不保证顺序。 但许多业务需要可靠性:日志上报、订单同步、状态更新等。 因此需要在应用层补齐可靠性能力。 核心概念 ACK 确认:接收方回执 超时重传:超时未确认就重发 序列号:保证顺序与去重 窗口机制:提升吞吐(Stop-and-Wait / Sliding Window) 实践指南 / 步骤 每个消息加序列号 接收端发送 ACK 发送端设置超时重传 去重与乱序处理 必要时加入滑动窗口 可运行示例 下面用“丢包概率 + 重试”模拟可靠发送: import random import time def unreliable_send(loss_rate: float) -> bool: return random.random() > loss_rate def send_reliable(data: str, loss_rate=0.3, timeout=0.1, max_retry=10): for attempt in range(1, max_retry + 1): ok = unreliable_send(loss_rate) if ok: return attempt time.sleep(timeout) return None if __name__ == "__main__": tries = send_reliable("hello", loss_rate=0.4) print("delivered after", tries, "tries") 解释与原理 可靠传输的本质是“在不可靠通道上建立协议保障”。 ACK 表示已收到,超时重传保证最终送达,序列号避免重复与乱序。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

为什么打开 TCP 套接字开销大:握手、状态与系统成本

副标题 / 摘要 TCP 连接不是一次函数调用,而是一组协议状态机与内核资源分配。本文解释开销来源,并给出工程上的优化路径。 目标读者 负责网络服务优化的后端工程师 想理解连接成本的系统开发者 需要排查连接耗时的运维与 SRE 背景 / 动机 在高并发系统里,“频繁建连”常常成为性能瓶颈。 理解 TCP 连接开销来源,才能知道何时该用连接池、何时该复用、何时该改协议。 核心概念 三次握手:SYN/SYN-ACK/ACK 内核状态:连接表、套接字缓冲区、TCP 状态机 慢启动:初始窗口小、吞吐从低到高 系统调用成本:socket/connect/accept 带来上下文切换 实践指南 / 步骤 优先复用连接(HTTP keep-alive / 连接池) 减少短连接,批量或长连接替代 降低握手成本(TLS session resumption) 调优内核参数(连接队列、端口范围) 监控连接层指标(SYN 重传、TIME_WAIT) 可运行示例 下面脚本在本机测量多次建连成本: import socket import threading import time def server(port_holder, ready, n): s = socket.socket() s.bind(("127.0.0.1", 0)) port_holder.append(s.getsockname()[1]) s.listen() ready.set() for _ in range(n): conn, _ = s.accept() conn.close() s.close() def measure(n=200): port_holder = [] ready = threading.Event() t = threading.Thread(target=server, args=(port_holder, ready, n), daemon=True) t.start() ready.wait() port = port_holder[0] start = time.perf_counter() for _ in range(n): c = socket.create_connection(("127.0.0.1", port)) c.close() elapsed = time.perf_counter() - start print(f"{n} connections: {elapsed:.3f}s") if __name__ == "__main__": measure() 解释与原理 TCP 连接要维护状态机、缓冲区、窗口、重传计时器。 每次建连都需要三次握手与内核资源分配,还会触发慢启动,吞吐无法立即拉满。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

TCP 与 HTTP 的区别:分层、语义与选型

副标题 / 摘要 TCP 是传输层协议,HTTP 是应用层协议。二者的职责与语义完全不同,但经常被混淆。本文用工程视角梳理差异与选型。 目标读者 需要排查网络问题的后端工程师 想理解协议分层的开发者 Web 服务与客户端开发人员 背景 / 动机 很多线上问题都源于“层次混淆”:把 HTTP 的问题当 TCP 处理,或把 TCP 的问题当 HTTP 处理。 理解分层,是定位问题与做技术选型的基础。 核心概念 TCP:可靠、面向连接的字节流传输 HTTP:在传输层之上定义请求/响应语义 分层模型:传输层解决“怎么送到”,应用层解决“送什么” 实践指南 / 步骤 先看连接层:是否能建立 TCP 连接(握手、丢包、重传) 再看应用层:请求是否符合 HTTP 协议(方法、头、状态码) 分层排查:TCP 通了但 HTTP 失败,多半是应用层问题 选型时分清职责:HTTP 可以跑在 TCP 或 QUIC 上 常用诊断命令: # 看 TCP 连接建立 nc -vz host 80 # 看 HTTP 层返回 curl -v http://host/ 可运行示例 先在本机启动一个 HTTP 服务: python3 -m http.server 8000 再用 socket 直接发 HTTP 请求: ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]