--- tags: [计算机网络, DNS, DHCP, WebSocket] create time: 2026-05-18 03:10 --- # DNS / DHCP / WebSocket ## 一、DNS 原理与优化 ### DNS 查询流程(递归 vs 迭代) ```mermaid sequenceDiagram participant U as 用户浏览器 participant LRD as 本地 DNS Resolver
ISP 或 1.1.1.1/9.9.9.9 participant TLD as TLD Server
.com participant AUTH as Authoritative NS
example.com U->>LRD: 递归查询 "example.com?" Note over LRD: 检查本地缓存... LRD->>TLD: 迭代查询 ".com?" TLD-->>LRD: "去问 example.com 的 NS" LRD->>AUTH: 迭代查询 "example.com A 记录?" AUTH-->>LRD: 93.184.216.34 Note over LRD: TTL=300 → 缓存 5 分钟 LRD-->>U: ✅ 93.184.216.34 ``` ### 关键概念 | 术语 | 说明 | |------|------| | **Recursion Desired (RD)** | 客户端要求 DNS 服务器递归查找 | | **Authority Section** | 指向下一级的授权 NS | | **CNAME Chain** | 别名链,最多 63 层嵌套 | | **TTL** | Time To Live,缓存有效期(秒) | | **ANAME/ALIAS** | 根域名的 CNAME 替代方案 | | **Any 查询** | `query type = ANY`,RFC 8753 建议禁用 | ### 常见记录类型 | 类型 | 名称 | 用途 | 示例 | |------|------|------|------| | A | Address | IPv4 地址 | `@ A 93.184.216.34` | | AAAA | Address V6 | IPv6 地址 | `@ AAAA 2606:2800:220:1:248:1893:25c8:1946` | | CNAME | Canonical Name | 别名 | `www CNAME example.com` | | MX | Mail Exchange | 邮件服务器优先级 | `@ MX 10 mail.example.com` | | TXT | Text | SPF/DKIM/域名验证 | `v=spf1 include:_spf.google.com ~all` | | SRV | Service | 服务定位 | `_sip._tcp SVC 1 0 5060 sip.example.com` | | NS | Name Server | 授权 NS 记录 | `@ NS ns1.provider.com` | | PTR | Pointer | 反向解析 (IP → 域名) | `34.216.184.93.in-addr.arpa PTR example.com` | | SOA | Start of Authority | 区域文件起始权威记录 | `ns1 admin email serial refresh retry expire minimum` | | DS / DNSKEY | — | DNSSEC 签名验证 | — | ### DNS 缓存层次 ``` ┌─────────────────────────────────────┐ │ Tier 1: Application/CPU Cache │ ← Go sync.Map / HTTP cache header │ TTL controlled by Content-TTL │ Browser cache varies 0~30min ├─────────────────────────────────────┤ │ Tier 2: OS Resolver Cache │ ← nscd / systemd-resolved / DNSMasq │ Linux: nscd (default off!) │ macOS: mDNSResponder │ macOS: mDNSResponder (~120s) │ Windows: Dnscache ├─────────────────────────────────────┤ │ Tier 3: ISP / Recursive Resolver │ ← Cloudflare 1.1.1.1, Google 8.8.8.8 │ TTL from authoritative server │ 通常 60~300s 最小缓存 ├─────────────────────────────────────┤ │ Tier 4: TLD + Authoritative │ ← .com NS → example.com NS │ No user-controlable caching │ └─────────────────────────────────────┘ ``` ### DNS-over-HTTPS / DNS-over-TLS | 协议 | RFC | 端口 | 特点 | |------|-----|------|------| | DoH (DNS over HTTPS) | 8484 | 443 (TCP) | 伪装成 HTTPS 流量,CDN 友好 | | DoT (DNS over TLS) | 7858 | 853 (TCP) | 专用加密通道 | | DoQ (DNS over QUIC) | 9230 | 853 (UDP via QUIC) | HTTP/3 风格 | ```bash # Linux 启用 DoH $ resolvectl dns eth0 1.1.1.1 $ resolvectl domain eth0 "~." # dig 指定 DNS 服务器 $ dig @1.1.1.1 example.com +short 93.184.216.34 ``` ## 二、DHCP 自动分配 ### DHCP 四步交互(DORA) ```mermaid sequenceDiagram participant Client as 新设备
(无 IP) participant Server as DHCP Server Note over Client: BOOTING state, src_ip=0.0.0.0 Client->>Server: DHCPDISCOVER (broadcast ff:ff:ff:ff:ff:ff) Note over Server: 收到后从可用池选择一个 IP Server-->>Client: DHCPOFFER (ip=x.x.x.x, lease_time=T, gw=y.y.y.y) Note over Client: SELECTING state Client->>Server: DHCPREQUEST (requested ip=x.x.x.x) Note over Server: 确认分配 Server-->>Client: DHCPACK (confirmed allocation) Note over Client: BOUND state ✅ IP = x.x.x.x ``` ### DHCP 续租机制 ``` 租约时间 = Lease Time(默认通常 24h) 续约时机: • T1 = 50% 租约时 → RENEW (单播到原服务器) • T2 = 87.5% 租约时 → REBIND (广播到新服务器) • 到期前必须续约成功,否则释放 IP ``` ```bash # Linux DHCP 客户端配置 $ cat /etc/dhcp/dhclient.conf timeout 300; # 超时重试间隔 retry 60; # 初始重试间隔 reboot 10; # 重启时重尝试获取 IP request subnet-mask, broadcast-address, time-offset, routers; # 手动刷新 IP $ sudo dhclient -r eth0 # release $ sudo dhclient eth0 # request new ``` ## 三、WebSocket 全双工通信 ### 为什么需要 WebSocket? ``` 传统轮询 vs WebSocket: ═══════════════════════ Polling: Client ─→ GET /status ─→ empty Client ─→ GET /status ─→ {"msg": "hi"} Client ─→ GET /status ─→ empty ... 浪费带宽,延迟高 Long Polling: Client ─→ GET /status (挂起) ─→ ...等待... ─→ {"msg": "hi"} Client ─→ GET /status (再挂起) ─→ ... WebSocket ✨: Client ─── 握手升级 ───→ 持久双向通道 Server ─── 推送消息 ───→ Client Client ─── 推送消息 ───→ Server ← 全双工、低开销! --> ``` ### WebSocket 握手升级过程 ``` HTTP 请求 → WebSocket → HTTP 响应 Client: Server: GET /ws/chat HTTP/1.1 101 Switching Protocols Host: chat.example.com Upgrade: websocket Upgrade: websocket Connection: Upgrade Connection: Upgrade Sec-WebSocket-Accept: Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 ``` **关键:** 这不是 TCP 层面的升级,而是 HTTP 协议的升级——服务器返回 `101` 状态码告诉客户端:"好的,我们从这里开始用 WebSocket 协议"。 ### Sec-WebSocket-Accept 计算 ```go import ( "crypto/sha1" "encoding/base64" "strings" ) const magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" func computeAccept(key string) string { h := sha1.New() h.Write([]byte(key + magicGUID)) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } // 例: key = "dGhlIHNhbXBsZSBub25jZQ==" // accept = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" ``` ### WebSocket Frame 格式 ``` ┌───────────┬───────────┬─────────────┬───────────────┬────────────────┐ │ FIN(1 bit)│ RSV(3bit) │ Opcode(4bit)│ Mask(1 bit) │ Payload Len │ │ │ │ │ │ + Ext Len │ ├───────────┴───────────┴─────────────┴───────────────┼────────────────┤ │ Extended Payload Length │ Mask Key │ │ (0, 126, or 127 bytes) │ (4 bytes) │ ├─────────────────────────────────────────────────────┴────────────────┤ │ Masked Payload Data (variable) │ └─────────────────────────────────────────────────────────────────────┘ ``` | Opcode | 含义 | |--------|------| | 0x0 | Continuation frame | | 0x1 | Text frame | | 0x2 | Binary frame | | 0x8 | Connection Close | | 0x9 | Ping | | 0xA | Pong | ### Go 中的 WebSocket ```go package main import ( "log" "net/http" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true // 生产环境应严格校验 Origin }, } func wsHandler(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println("upgrade error:", err) return } defer conn.Close() for { mt, message, err := conn.ReadMessage() if err != nil { break } log.Printf("recv: %s", message) conn.WriteMessage(mt, message) } } func main() { http.HandleFunc("/ws", wsHandler) log.Fatal(http.ListenAndServe(":8080", nil)) } ``` ## 关联笔记 - [[hhs/NETWORK/HTTPS与TLS握手]] — SNI 扩展在 DNS 解析中的应用 - [[hhs/NETWORK/WebSocket全双工通信]] — 心跳机制防止 NAT/代理超时断开 - [[hhs/NETWORK/NAT原理与应用]] — WebSocket 也受 NAT 影响