HTTP Server 例程讲解#
例程位置#
开发板固件路径:
/sdcard/examples/14-Socket/http_server.pySDK 源码路径:
src/canmv/resources/examples/14-Socket/http_server.py
该例程在开发板上启动一个简单的 HTTP/1.1 服务。浏览器连接 8081 端口后,服务
读取请求头并返回设备状态网页,展示系统版本、运行时间、可用内存、网卡和客户端
信息,然后关闭连接并退出。
运行前准备#
在脚本顶部设置网络类型和 Wi-Fi 参数:
NETWORK_TYPE = "wifi_sta" # "default"、"lan"、"wifi_sta" 或 "wifi_ap"
WLAN_DEVICE = "auto" # "auto"、"usb"、"sdio" 或 "spi"
WIFI_SSID = "TEST"
WIFI_PASSWORD = "12345678"
NETWORK_TIMEOUT = 20
浏览器和开发板必须处于可互通的网络。wifi_ap 模式下,先让电脑连接开发板创建的
热点;wifi_sta 或 lan 模式下,两端应位于同一局域网或具有可达路由。
代码流程#
联网并取得服务地址#
netif, ip = connect_network(
NETWORK_TYPE,
ssid=WIFI_SSID,
password=WIFI_PASSWORD,
wlan_device=WLAN_DEVICE,
timeout=NETWORK_TIMEOUT,
)
返回的 ip 用于打印浏览器访问地址。
创建监听 Socket#
s = socket.socket()
addr = socket.getaddrinfo("0.0.0.0", 8081)[0][-1]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
0.0.0.0表示监听当前所有 IPv4 接口,不依赖动态生成的网卡名称。SO_REUSEADDR允许脚本重启后尽快重新绑定端口。listen(5)开始监听 TCP 连接,参数5是等待处理连接的队列上限。
接收浏览器连接#
while True:
try:
client, client_address = server.accept()
break
except OSError as error:
if error.errno != 11:
raise
os.exitpoint()
time.sleep_ms(10)
RT-Smart Socket 的 accept() 在当前没有连接时会返回 EAGAIN。例程对此进行
短暂等待并重试,同时调用 os.exitpoint() 保持脚本可退出。接受连接后,串口会
打印浏览器地址,再由 read_request() 把客户端 Socket 设为非阻塞模式。
读取完整请求头#
request = bytearray()
client.setblocking(False)
while len(request) < MAX_REQUEST_BYTES:
chunk = client.recv(min(256, MAX_REQUEST_BYTES - len(request)))
if chunk:
request.extend(chunk)
if request.find(b"\r\n\r\n") >= 0:
break
HTTP 请求头以空行结束,即字节序列 \r\n\r\n。一次 recv() 不保证取得完整
请求,因此例程把每个分片追加到 bytearray,直到请求头完整。请求最大为 4096
字节,等待时间为 2 秒,避免异常客户端无限占用服务。
生成设备状态页#
info = network_info(netif)
config = info["ifconfig"]
system = os.uname()
network_info() 汇总当前接口名称、默认接口、连接状态、IP 配置和 MAC 地址;
os.uname() 提供开发板名称、CanMV 固件版本和 MicroPython 构建信息。页面还显示
gc.mem_free() 返回的可用堆内存、运行时间、全部已注册网卡和浏览器地址。
所有动态值先经过 html_escape(),再写入响应正文,避免设备名或请求端信息破坏
HTML 结构。
返回响应并退出#
body = build_status_page(netif, client_address, counter)
header = (
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"\r\n"
) % len(body)
client.setblocking(True)
client.sendall(header.encode() + body)
响应使用 HTTP 要求的 CRLF 行结束符,并通过 Content-Length 明确正文长度。
sendall() 会在关闭连接前完整发送响应。客户端和监听 Socket 都在 finally 中
关闭。这个教学例程只处理一个成功请求;再次访问前需要重新运行脚本。
运行与验证#
运行脚本并查看串口打印的
http://<IP>:8081/。在可访问开发板的浏览器中打开该地址。
页面应显示 System、Request 和 Network 三组设备信息,串口会打印原始请求。
访问超时时,依次检查两端是否互通、IP 是否仍有效,以及 TCP 8081 端口是否被
防火墙拦截。
