1. TCP/IP 协议栈

互联网通信建立在分层协议栈上。理解每一层的职责,是理解服务器工作原理的前提。

5
应用层 Application Layer
HTTP / HTTPS / WebSocket / gRPC / DNS
4
传输层 Transport Layer
TCP(可靠传输、三次握手) / UDP(高速、无连接)
3
网络层 Network Layer
IP 寻址、路由转发、TTL / ICMP
2
数据链路层 Data Link Layer
Ethernet / WiFi / MAC 地址、帧封装
1
物理层 Physical Layer
网线、光纤、无线信号、比特流传输

TCP 三次握手与四次挥手

客户端 (Client)
服务器 (Server)
— 三次握手 (建立连接) —
SYN (seq=x)
第 1 次:我想连接
SYN+ACK (seq=y, ack=x+1)
第 2 次:好的,我准备好了
ACK (ack=y+1)
第 3 次:确认,连接建立 ✓
— 数据传输 —
HTTP 请求/响应、数据流
DATA 双向传输
— 四次挥手 (关闭连接) —
FIN
客户端:我发完了
ACK
服务器:收到,等我也发完
FIN
服务器:我也发完了
ACK
客户端:确认,连接关闭 ✓

用 Go 演示 TCP 服务器

package main

import (
    "bufio"
    "fmt"
    "net"
    "strings"
)

func main() {
    // 监听 TCP 端口 8080
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        panic(err)
    }
    defer listener.Close()
    fmt.Println("TCP 服务器启动,监听 :8080")

    for {
        // 阻塞等待客户端连接
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        // 每个连接开一个 goroutine 处理 (并发核心)
        go handleConn(conn)
    }
}

func handleConn(conn net.Conn) {
    defer conn.Close()
    remote := conn.RemoteAddr().String()
    fmt.Printf("新连接: %s\n", remote)

    scanner := bufio.NewScanner(conn)
    for scanner.Scan() {
        line := scanner.Text()
        fmt.Printf("[%s] 收到: %s\n", remote, line)
        // Echo: 回显数据
        response := strings.ToUpper(line) + "\n"
        conn.Write([]byte(response))
    }
    fmt.Printf("连接断开: %s\n", remote)
}

2. HTTP 协议深度解析

HTTP 版本演进

版本年份核心特性问题
HTTP/1.01996短连接,每次请求新建TCP性能差,连接开销大
HTTP/1.11997持久连接 Keep-Alive,管道化队头阻塞 (HOL blocking)
HTTP/22015多路复用、头部压缩、服务器推送TCP 层队头阻塞
HTTP/32022基于 QUIC/UDP,彻底解决队头阻塞普及率还在提升

HTTP 请求结构

请求行
POST /api/users HTTP/1.1
请求头
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGc...
Content-Length: 45
空行
(必须,分隔请求头与请求体)
请求体
{"name": "Alice", "email": "alice@test.com"}

HTTP 状态码速查

2xx 成功

  • 200 OK — 请求成功
  • 201 Created — 资源已创建
  • 204 No Content — 成功,无返回体
  • 206 Partial Content — 范围请求成功

4xx 客户端错误

  • 400 Bad Request — 请求格式错误
  • 401 Unauthorized — 未认证
  • 403 Forbidden — 无权限
  • 404 Not Found — 资源不存在
  • 429 Too Many Requests — 限流

5xx 服务器错误

  • 500 Internal Server Error — 服务器异常
  • 502 Bad Gateway — 网关错误
  • 503 Service Unavailable — 服务不可用
  • 504 Gateway Timeout — 网关超时

3xx 重定向

  • 301 Moved Permanently — 永久重定向
  • 302 Found — 临时重定向
  • 304 Not Modified — 缓存未修改
  • 307 Temporary Redirect — 临时(保持方法)

用 Go 标准库实现 HTTP 服务器

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "time"
)

type Response struct {
    Status  string `json:"status"`
    Message string `json:"message"`
    Time    string `json:"time"`
}

func main() {
    mux := http.NewServeMux()

    // 路由注册
    mux.HandleFunc("GET /", homeHandler)
    mux.HandleFunc("GET /health", healthHandler)
    mux.HandleFunc("POST /echo", echoHandler)

    // 服务器配置 (生产环境必须设置超时)
    server := &http.Server{
        Addr:         ":8080",
        Handler:      loggingMiddleware(mux),
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  30 * time.Second,
    }

    fmt.Println("HTTP 服务器启动: http://localhost:8080")
    log.Fatal(server.ListenAndServe())
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(Response{
        Status:  "ok",
        Message: "Welcome to Go Server!",
        Time:    time.Now().Format(time.RFC3339),
    })
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]string{"status": "healthy"})
}

func echoHandler(w http.ResponseWriter, r *http.Request) {
    var body map[string]any
    if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
        http.Error(w, "invalid JSON", http.StatusBadRequest)
        return
    }
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(body)
}

// 中间件:请求日志
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        log.Printf("%s %s %s %v", r.Method, r.URL.Path, r.RemoteAddr, time.Since(start))
    })
}

3. WebSocket 实时通信

WebSocket 在 HTTP 握手后升级为全双工 TCP 连接,服务器可主动推送数据,适合聊天室、实时通知、在线协作等场景。

客户端 (Client)
服务器 (Server)
— HTTP 升级握手 —
GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
发起 WebSocket 升级请求
HTTP/1.1 101 Switching Protocols
服务器同意升级,握手完成 ✓
— 全双工 WebSocket 通信 —
Text Frame: "Hello Server"
客户端随时推送消息
Text Frame: "Hello Client"
服务器主动推送,无需请求
保持连接活跃
Ping / Pong (心跳)
package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    // 生产环境应验证 Origin
    CheckOrigin: func(r *http.Request) bool { return true },
}

// Hub 管理所有 WebSocket 连接
type Hub struct {
    clients    map[*websocket.Conn]bool
    broadcast  chan []byte
    register   chan *websocket.Conn
    unregister chan *websocket.Conn
}

func newHub() *Hub {
    return &Hub{
        clients:    make(map[*websocket.Conn]bool),
        broadcast:  make(chan []byte, 256),
        register:   make(chan *websocket.Conn),
        unregister: make(chan *websocket.Conn),
    }
}

func (h *Hub) run() {
    for {
        select {
        case conn := <-h.register:
            h.clients[conn] = true
            fmt.Printf("客户端连接,当前连接数: %d\n", len(h.clients))

        case conn := <-h.unregister:
            if _, ok := h.clients[conn]; ok {
                delete(h.clients, conn)
                conn.Close()
                fmt.Printf("客户端断开,当前连接数: %d\n", len(h.clients))
            }

        case message := <-h.broadcast:
            // 广播给所有客户端
            for conn := range h.clients {
                if err := conn.WriteMessage(websocket.TextMessage, message); err != nil {
                    h.unregister <- conn
                }
            }
        }
    }
}

func wsHandler(hub *Hub, w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("WebSocket 升级失败:", err)
        return
    }
    hub.register <- conn

    // 读取消息并广播
    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            hub.unregister <- conn
            break
        }
        hub.broadcast <- msg
    }
}

func main() {
    hub := newHub()
    go hub.run()

    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        wsHandler(hub, w, r)
    })

    log.Println("WebSocket 服务器: ws://localhost:8080/ws")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

4. DNS 与服务发现

浏览器 输入域名
本地缓存 hosts / OS 缓存
递归 DNS ISP / 8.8.8.8
根 DNS 13 组根服务器
TLD DNS .com / .net
权威 DNS 返回 IP 地址
Web 服务器 TCP + HTTP
package main

import (
    "context"
    "fmt"
    "net"
    "time"
)

func dnsLookup(host string) {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    resolver := &net.Resolver{
        PreferGo: true,
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{Timeout: 3 * time.Second}
            // 使用 Google Public DNS
            return d.DialContext(ctx, "udp", "8.8.8.8:53")
        },
    }

    // 查询 A 记录 (IPv4)
    ips, err := resolver.LookupHost(ctx, host)
    if err != nil {
        fmt.Printf("DNS 查询失败: %v\n", err)
        return
    }
    fmt.Printf("主机 %s 的 IP 地址:\n", host)
    for _, ip := range ips {
        fmt.Printf("  → %s\n", ip)
    }

    // 查询 MX 记录 (邮件)
    mxs, _ := resolver.LookupMX(ctx, host)
    for _, mx := range mxs {
        fmt.Printf("MX: %s (优先级: %d)\n", mx.Host, mx.Pref)
    }
}

func main() {
    dnsLookup("github.com")
}

5. TLS/HTTPS 原理

TLS(Transport Layer Security)在 TCP 之上提供加密、认证和完整性保护。

🔒

TLS 1.3 握手只需 1-RTT

相比 TLS 1.2 的 2-RTT,TLS 1.3 合并了握手步骤,显著降低延迟。对于已知服务器还支持 0-RTT 恢复。

package main

import (
    "crypto/tls"
    "fmt"
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "HTTPS 连接成功! 协议: %s", r.Proto)
    })

    // TLS 配置 (推荐配置)
    tlsConfig := &tls.Config{
        MinVersion: tls.VersionTLS13,    // 最低 TLS 1.3
        CurvePreferences: []tls.CurveID{
            tls.X25519,                  // 首选现代曲线
            tls.CurveP256,
        },
        CipherSuites: []uint16{          // TLS 1.3 自动选择,1.2 手动指定
            tls.TLS_AES_128_GCM_SHA256,
            tls.TLS_AES_256_GCM_SHA384,
        },
    }

    server := &http.Server{
        Addr:      ":443",
        Handler:   mux,
        TLSConfig: tlsConfig,
    }

    // 证书可通过 Let's Encrypt 自动获取
    log.Fatal(server.ListenAndServeTLS("cert.pem", "key.pem"))
}

// 自动 HTTPS (使用 autocert)
// import "golang.org/x/crypto/acme/autocert"
// m := &autocert.Manager{
//     Cache:      autocert.DirCache("certs"),
//     Prompt:     autocert.AcceptTOS,
//     HostPolicy: autocert.HostWhitelist("example.com"),
// }
// server.TLSConfig = m.TLSConfig()
💡

开发环境证书

使用 mkcert 工具快速生成本地可信证书:mkcert -install && mkcert localhost 127.0.0.1

6. 反向代理与负载均衡

客户端请求
Nginx / 负载均衡器
轮询 / 最少连接 / IP Hash
后端服务 1  :8081
后端服务 2  :8082
后端服务 3  :8083
package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "sync/atomic"
)

// 简易轮询负载均衡器
type LoadBalancer struct {
    backends []*url.URL
    counter  atomic.Uint64
}

func NewLoadBalancer(backends []string) *LoadBalancer {
    lb := &LoadBalancer{}
    for _, b := range backends {
        u, _ := url.Parse(b)
        lb.backends = append(lb.backends, u)
    }
    return lb
}

func (lb *LoadBalancer) next() *url.URL {
    idx := lb.counter.Add(1) % uint64(len(lb.backends))
    return lb.backends[idx]
}

func (lb *LoadBalancer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    target := lb.next()
    proxy := httputil.NewSingleHostReverseProxy(target)
    proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
        http.Error(w, "backend unavailable", http.StatusBadGateway)
    }
    proxy.ServeHTTP(w, r)
    fmt.Printf("请求转发到: %s\n", target.Host)
}

func main() {
    lb := NewLoadBalancer([]string{
        "http://localhost:8081",
        "http://localhost:8082",
        "http://localhost:8083",
    })
    log.Fatal(http.ListenAndServe(":80", lb))
}