網路基礎:TCP/IP 與 HTTP 協定

當你在瀏覽器輸入 https://www.google.com 並按下 Enter——這背後發生了什麼事?

這短短的一秒內,你的電腦經歷了 DNS 查詢 → TCP 握手 → TLS 加密 → HTTP 請求/回應 等一系列複雜過程。

🔥 Vibe Prompt

「用 Python 實作一個簡易 HTTP 伺服器,支援靜態檔案服務、路由處理、並顯示每個請求的 TCP 連線資訊。另外實作一個命令行 HTTP 用戶端,手動傳送 GET/POST 請求並解析回應。」

TCP/IP 協定棧

網路通訊不是一個單一的協定,而是一組分層協定:

| 層級 | 名稱 | 代表協定 | 職責 | |------|------|---------|------| | 4 | 應用層 | HTTP, DNS, SMTP | 提供應用程式之間的通訊服務 | | 3 | 傳輸層 | TCP, UDP | 端到端的可靠/不可靠傳輸 | | 2 | 網路層 | IP, ICMP | 路由與定址(找到對方位置) | | 1 | 網路介面層 | Ethernet, WiFi | 實體訊號傳輸 |

封裝過程

當你發送 HTTP 請求時,資料會像俄羅斯娃娃一樣被層層包裝:

[HTTP 資料] ← 應用層
[TCP 標頭 + HTTP 資料] ← 傳輸層
[IP 標頭 + TCP 標頭 + HTTP 資料] ← 網路層
[Ethernet 標頭 + IP 標頭 + TCP 標頭 + HTTP 資料 + 檢查碼] ← 網路介面層

TCP 的三次握手

TCP 是連線導向的協定,建立連線需要三次交握:

用戶端                         伺服器
   │                             │
   ├─── SYN (seq=x) ────────────►│  1. 我要連線
   │◄─── SYN+ACK (seq=y, ack=x+1)├─  2. 收到,我也要連線
   ├─── ACK (seq=x+1, ack=y+1)──►│  3. 好,連線建立
   │◄═══════════════════════════►│  連線已建立(資料傳輸)
import socket

# 簡易 TCP 伺服器
def simple_tcp_server():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('localhost', 8080))
    server.listen(5)
    print("🌐 TCP 伺服器啟動在 http://localhost:8080")
    
    while True:
        client, addr = server.accept()
        print(f"📩 收到連線: {addr}")
        data = client.recv(1024)
        response = b"""HTTP/1.1 200 OK
Content-Type: text/plain

Hello from TCP Server!"""
        client.send(response)
        client.close()

# 簡易 TCP 用戶端
def simple_tcp_client():
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(('localhost', 8080))
    client.send(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
    response = client.recv(4096)
    print(f"📬 伺服器回應:\n{response.decode()}")
    client.close()

HTTP 協定

HTTP (HyperText Transfer Protocol) 是網際網路的基石。

HTTP 請求結構

GET /index.html HTTP/1.1        ← 請求行(方法 + 路徑 + 版本)
Host: www.example.com            ← 標頭
User-Agent: Mozilla/5.0
Accept: text/html
                                 ← 空行
(請求主體 — 僅 POST/PUT 有)   ← 主體

HTTP 回應結構

HTTP/1.1 200 OK                  ← 狀態行(版本 + 狀態碼 + 訊息)
Content-Type: text/html          ← 標頭
Content-Length: 1234
Set-Cookie: session_id=abc123
                                 ← 空行
<!DOCTYPE html>                  ← 回應主體
<html>...

HTTP 狀態碼

| 狀態碼 | 類別 | 範例 | |--------|------|------| | 1xx | 資訊 | 100 Continue | | 2xx | 成功 | 200 OK, 201 Created, 204 No Content | | 3xx | 重新導向 | 301 Moved Permanently, 304 Not Modified | | 4xx | 用戶端錯誤 | 400 Bad Request, 401 Unauthorized, 404 Not Found | | 5xx | 伺服器錯誤 | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |

實作簡易 HTTP 框架

import socket
import threading

class SimpleHTTP:
    def __init__(self, host='localhost', port=8000):
        self.host = host
        self.port = port
        self.routes = {}
    
    def route(self, path, method='GET'):
        def wrapper(handler):
            self.routes[(method, path)] = handler
            return handler
        return wrapper
    
    def handle_request(self, client, addr):
        data = client.recv(8192).decode()
        if not data:
            client.close()
            return
        
        # 解析請求行
        request_line = data.split('\r\n')[0]
        method, path, _ = request_line.split(' ')
        
        print(f"➡️ {method} {path} from {addr}")
        
        # 尋找對應路由
        handler = self.routes.get((method, path))
        if handler:
            body = handler()
            response = f"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {len(body)}\r\n\r\n{body}"
        else:
            body = "<h1>404 Not Found</h1>"
            response = f"HTTP/1.1 404 Not Found\r\nContent-Length: {len(body)}\r\n\r\n{body}"
        
        client.send(response.encode())
        client.close()
    
    def start(self):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((self.host, self.port))
        server.listen(10)
        print(f"🚀 伺服器啟動: http://{self.host}:{self.port}")
        
        while True:
            client, addr = server.accept()
            thread = threading.Thread(target=self.handle_request, args=(client, addr))
            thread.start()

# 使用範例
app = SimpleHTTP()

@app.route('/')
def home():
    return "<h1>🏠 首頁</h1><p>歡迎來到簡易 HTTP 伺服器!</p>"

@app.route('/about')
def about():
    return "<h1>📖 關於</h1><p>這是用純 Python socket 實作的 HTTP 伺服器。</p>"

# 啟動(註解掉以避免阻塞)
# app.start()

DNS 解析

DNS (Domain Name System) 將人類可讀的網域名稱轉換為 IP 位址:

你在瀏覽器輸入 google.com
        ↓
瀏覽器查詢 DNS 快取 → 沒有
        ↓
查詢系統設定的 DNS 伺服器(如 8.8.8.8)
        ↓
DNS 伺服器回傳 142.250.190.46
        ↓
瀏覽器透過 IP 位址建立 TCP 連線
import socket

# DNS 查詢範例
def dns_lookup(domain):
    try:
        ip = socket.gethostbyname(domain)
        print(f"🔍 {domain} → {ip}")
        return ip
    except socket.gaierror as e:
        print(f"❌ DNS 查詢失敗: {e}")
        return None

# 查詢常見網站
sites = ['google.com', 'github.com', 'stackoverflow.com']
for site in sites:
    dns_lookup(site)

HTTPS 與 TLS

HTTP 是明碼傳輸,所有資料(包含密碼、信用卡號)都可以被攔截。HTTPS (HTTP Secure) 在 HTTP 和 TCP 之間加入了一層 TLS (Transport Layer Security) 加密:

HTTP/1.1 200 OK     ← 明文
    ↓
TLS 加密層         ← 資料被加密
    ↓
TCP 傳輸           ← 加密後的資料在網路上傳輸

TLS 握手過程

客戶端                        伺服器
  │                              │
  ├── ClientHello ──────────────►│  支援的加密套件、TLS 版本
  │◄── ServerHello ──────────────┤  選擇的加密套件、憑證
  │◄── Certificate ──────────────┤  伺服器憑證(含公開金鑰)
  ├── 金鑰交換 ────────────────►│  產生對稱金鑰
  │◄════════════════════════════►│  加密通訊開始

HTTP/2 與 HTTP/3

| 版本 | 特性 | 優勢 | |------|------|------| | HTTP/1.1 | 序列請求、連線無法重用 | 簡單、普及 | | HTTP/2 | 多工串流、header 壓縮、伺服器推送 | 減少延遲 | | HTTP/3 | 基於 QUIC (UDP) | 更快連線建立、更好的弱網表現 |

RESTful API 設計

GET    /api/users        ← 取得使用者列表
GET    /api/users/123    ← 取得特定使用者
POST   /api/users        ← 建立新使用者
PUT    /api/users/123    ← 更新使用者
DELETE /api/users/123    ← 刪除使用者

REST 原則

  • 無狀態 (Stateless):每個請求包含所有必要資訊
  • 資源導向 (Resource-Oriented):URL 表示資源
  • 統一介面 (Uniform Interface):HTTP 方法表示操作

WebSocket

HTTP 是「請求-回應」模式,伺服器無法主動推送資料。WebSocket 建立持久連線,允許雙方隨時發送資料:

# WebSocket 服務端(使用 FastAPI)
from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"收到: {data}")

負載均衡 (Load Balancing)

使用者 ─── DNS ─── Load Balancer ─── 伺服器 1
                                 ─── 伺服器 2
                                 ─── 伺服器 3

| 演算法 | 策略 | |--------|------| | Round Robin | 輪流分配請求 | | Least Connections | 分配給連線數最少的伺服器 | | IP Hash | 同一 IP 固定到同一伺服器 | | Weighted | 根據伺服器能力分配權重 |

CDN (Content Delivery Network)

CDN 將靜態資源快取到全球各地的邊緣節點,讓使用者從最近的節點取得資料:

使用者(東京)→ 東京 CDN 邊緣節點(快取)→ 原始伺服器(美國)
使用者(倫敦)→ 倫敦 CDN 邊緣節點(快取)→ 原始伺服器(美國)

本章總結

| 概念 | 核心重點 | |------|---------| | TCP/IP | 分層協定棧,每層負責不同功能 | | 三次握手 | 確保雙方準備好通訊 | | HTTP | 請求-回應模型,無狀態協定 | | HTTPS/TLS | HTTP + 加密層,保護資料安全 | | HTTP/2 | 多工串流、header 壓縮 | | HTTP/3 (QUIC) | 基於 UDP,更快連線建立 | | DNS | 網域名稱解析為 IP 位址 | | RESTful API | 資源導向的 API 設計風格 | | WebSocket | 持久連線,雙向即時通訊 | | 負載均衡 | 分散流量到多台伺服器 | | CDN | 邊緣快取,加速全球存取 |

實戰練習

💡 Vibe Coding 練習:請 AI 建立一個「網路通訊互動式學習工具」:

  1. TCP 握手模擬:可視化展示 SYN、SYN-ACK、ACK 三次握手
  2. HTTP 偵測器:捕獲並解析 HTTP 請求/回應,顯示所有標頭
  3. TLS 握手展示:逐步展示 ClientHello → ServerHello → 金鑰交換
  4. REST API 測試工具:輸入端點和方法,發送請求並顯示結果
  5. WebSocket 聊天室:建立即時雙向通訊的展示
  6. CDN 模擬:顯示不同地理位置的存取延遲差異

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!