網路基礎: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)

總結

| 概念 | 重點 | |------|------| | TCP/IP | 分層協定棧,每層負責不同的功能 | | 三次握手 | 確保雙方都準備好通訊 | | HTTP | 請求-回應模型,無狀態協定 | | 狀態碼 | 2xx 成功, 3xx 重新導向, 4xx 用戶端錯誤, 5xx 伺服器錯誤 | | DNS | 將網域名稱解析為 IP 位址 |

實戰練習

💡 Vibe Coding 練習:請 AI 建立一個「HTTP 偵測與分析工具」:

  1. 實作 TCP 連線監聽,捕獲 HTTP 請求
  2. 解析請求行、標頭、主體
  3. 顯示 TCP 連線狀態(SYN, SYN-ACK, ACK)
  4. 支援 HTTPS 的 TLS 握手過程概覽
  5. 提供 Web 介面即時查看請求

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!