網路基礎: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 偵測與分析工具」:
- 實作 TCP 連線監聽,捕獲 HTTP 請求
- 解析請求行、標頭、主體
- 顯示 TCP 連線狀態(SYN, SYN-ACK, ACK)
- 支援 HTTPS 的 TLS 握手過程概覽
- 提供 Web 介面即時查看請求