網頁伺服器是負責處理客戶端(通常是網頁瀏覽器)發出的請求,並將所需的網頁或資料返回給客戶端的軟體系統。以下是網頁伺服器工作原理的簡單介紹:
當你在瀏覽器中輸入一個網址並按下 Enter,瀏覽器會產生一個 HTTP 或 HTTPS 請求。這個請求通常包含了想要訪問的資源路徑(如一個網頁)以及所需的其他信息(如使用的 HTTP 方法,常見的有 GET 或 POST)。
請求發出後,瀏覽器會首先與 DNS 伺服器通訊,將用戶輸入的網址(域名)轉換為對應的 IP 位址。這個 IP 位址用來標識網頁伺服器的位置。
瀏覽器根據解析出的 IP 位址,通過 TCP/IP 協議與目標網頁伺服器建立連接。這通常是在 80(HTTP)或 443(HTTPS)端口上進行的。
網頁伺服器接收到請求後,會根據請求的內容來決定應該返回哪些資源。伺服器可能會從其本地檔案系統中讀取靜態檔案(如 HTML、CSS、JavaScript、圖片等),也可能會執行伺服器端的腳本(如 PHP、Python、Node.js 等)來生成動態內容。
網頁伺服器生成對應的 HTTP 響應,響應中包含了狀態碼(例如 200 表示成功,404 表示資源未找到)、標頭(如內容類型、緩存指令等)以及請求的內容。然後,伺服器將這些信息透過之前建立的 TCP 連接發回到客戶端。
瀏覽器接收到伺服器的響應後,根據 HTML、CSS 和 JavaScript 來解析和呈現網頁。如果網頁中有其他資源(如圖片、外部樣式表或 JavaScript 檔案),瀏覽器會發出額外的 HTTP 請求來獲取這些資源,並最終將整個網頁呈現給用戶。
在響應結束後,伺服器會關閉與客戶端的連接,除非使用了 HTTP/2 或其他支持持久連接的技術,這些技術可以讓多個請求使用同一個連接,減少開銷。
在 MicroPython 上,可以使用內建的 socket 模組來建立簡單的網頁伺服器。這個模組允許你在 WiFi 支援的開發板(例如 ESP8266 或 ESP32)上運行一個基礎的 HTTP 伺服器,從而提供簡單的網頁服務。
Socket 模組主要功能:
socket 模組讓你能夠建立一個網路連線,這個連線可以是 TCP 或 UDP。TCP 是比較可靠的資料傳輸方式,確保資料完整地送到對方;而 UDP 則是比較輕量級的傳輸方式,適合用在即時性較高的應用上,比如影音串流。
你可以用 socket 模組來建立一個簡單的伺服器,這樣其他裝置就可以連到你的玩學機,並進行互動。例如,你可以建立一個 HTTP 伺服器來回應簡單的網頁請求,這在 IoT 領域非常常見。
玩學機也可以作為客戶端,連接到網際網路上的其他伺服器,比如連接到一個天氣伺服器來獲取天氣資料,或者連到一個 MQTT 伺服器進行即時消息的收發。
透過 send 和 recv 這些方法,可以傳送或接收字串、數據或是二進制資料。這對於控制遠端裝置或是接收感測器數據非常有用。
應用實例:
有兩台玩學機,機器 A 是當伺服器,機器 B 是客戶端(Clinet)。機器 A 隨時等待來自機器 B 的控制指令。機器 B 也可以換成你的手機或另一台 Wi-Fi 裝置,當你用機器 B 發出指令時,機器 A 就會接收並執行,可能是開關燈或讀取感測器的數據,並將結果回傳給機器 B。
import network
def connect(ssid, password):
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
while not station.isconnected():
pass
print('WiFi 連接成功')
print('IP 設定:', station.ifconfig())
return station
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>玩學機測試網頁</title>
</head>
<body>
歡迎您來到玩學機的測試網頁
</body>
</html>
# 簡單WebServer 程式
import socket
import wifi
# 設定 WiFi 連線參數
SSID = '你家無線網路的SSID'
PASSWORD = '你家無線網路的密碼'
# 連接 WiFi
station = wifi.connect(SSID, PASSWORD)
# 其他主程式邏輯
# 例如:啟動網頁伺服器或其他應用
# 讀取 index.html 檔案的內容
def read_html_file():
try:
with open('index.html', 'r') as file:
return file.read()
except Exception as e:
print("無法讀取 index.html 檔案:", e)
return "<h1>500 Internal Server Error</h1>"
# 建立 socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('伺服器啟動,等待連接...')
while True:
cl, addr = s.accept()
print('客戶端連接來自', addr)
# 接收 HTTP 請求
request = cl.recv(1024)
print('請求內容:', request)
# 讀取並發送 index.html 檔案的內容
response = read_html_file()
cl.send('HTTP/1.1 200 OK\r\n')
cl.send('Content-Type: text/html\r\n')
cl.send('Connection: close\r\n\r\n')
cl.sendall(response)
# 關閉連接
cl.close()