MicroPython ESP8266 网络编程实战:基于 TCP Socket 的客户端与服务器开发指南 📅 发布时间:2026/9/20 11:58:45 👁 浏览次数: 嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载导读TCP Socket 是互联网应用最基础的通信构件——它能够在两个网络设备之间建立一条可靠的字节流通道HTTP、telnet、SSH、SMTP 等上层协议全部构建在它之上。本教程基于 MicroPython 官方 ESP8266 教程的《Network - TCP sockets》章节以乐鑫 ESP8266 开发板为核心手把手带你完成三个实战项目通过 telnet 服务流式拉取 Star Wars Ascii 动画、用 HTTP GET 请求下载网页、以及在本机上搭建一个展示全部 GPIO 引脚状态的 HTTP 服务器。读完本文你将掌握socket模块的核心 API 用法、getaddrinfo地址解析的正确姿势、客户端与服务器两种编程模型并能直接在 REPL 或boot.py中落地运行。前置要求本文所有示例都假设你的 ESP8266 已经通过network.WLAN成功接入 WiFi可参考 ESP8266 网络基础教程。Socket 模块的完整 API 参考见 socket 模块文档。TCP Socket 是什么互联网的可靠字节流在深入代码之前先建立对 TCP Socket 的直观认识**Socket套接字**是网络设备上的一个端点。当两个设备上的 socket 连接在一起通信就可以进行。可以把 socket 想象成两台设备之间的一条虚拟管道。可靠字节流与 UDP 的无连接、不保证送达不同TCP 保证数据按序、不丢失地传输因此适合承载 HTTP、telnet、SSH 这类对数据完整性要求高的协议。端口Port每个上层协议都绑定一个固定的整数端口例如 HTTP 是 80、telnet 是 23、SSH 是 22。给定IP 地址 端口号你就能定位并连接到一个远程设备上的特定服务。在 MicroPython 中socket模块提供对 BSD socket 接口的访问。它与 CPython 最大的差异在于MicroPython 的 socket 对象直接实现了 stream文件类接口而 CPython 需要用makefile()转换在 MicroPython 中makefile()仍然存在但只是空操作socket 模块文档 明确指出调用它仅为保持与 CPython 的兼容性。地址解析getaddrinfo 的正确用法所有网络程序的第一步都是把主机名 端口解析成可连接的地址。MicroPython 的规范做法是使用socket.getaddrinfo(host, port) import socket addr_info socket.getaddrinfo(towel.blinkenlights.nl, 23)这个函数返回的是一个5 元组列表每个元组结构为(family, type, proto, canonname, sockaddr)。以addr_info[0][-1]取到最后一个元素就是(ip, port)形式的可直接连接的地址 addr addr_info[0][-1]如果你在 REPL 里分别输入addr_info和addr会直观看到两者保存的信息差异——前者是包含地址族、socket 类型、协议等完整信息的列表后者只是我们实际需要的 IP 与端口对。从源码层面看extmod/modsocket.c 中mod_socket_getaddrinfo的实现揭示了它的内部行为先尝试把主机名当 IP 地址解析如果传入的字符串本身就是点分十进制形式如10.10.10.10直接通过netutils_parse_ipv4_addr解析跳过 DNS 查询否则遍历已注册的网卡NIC在所有mod_network_nic_list中的网卡里寻找实现了gethostbyname协议的网卡执行 DNS 查询找不到可用网卡时抛出OSError(no available NIC)组装 5 元组返回固定返回AF_INET、SOCK_STREAM类型的地址元组。getaddrinfo还支持最多 6 个参数host, port, af, type, proto, flags用于过滤地址族与 socket 类型例如socket.getaddrinfo(host, 80, 0, socket.SOCK_STREAM)可保证返回的地址适合流式连接。官方文档建议在编写可移植程序时始终使用getaddrinfo即使地址是数字形式也应如此——这是最高效且最可移植的地址处理方式。仓库中的 tests/net_inet/getaddrinfo.py 覆盖了该函数的各类边界情况不存在的域名、非法主机名、纯 IP 地址、0.0.0.0以及有效域名全部用try/except OSError包裹验证其异常行为可作为你测试网络解析的参考模板。实战一连接 telnet 服务流式下载 Star Wars Ascii 动画blinkenlights.nl 网站的 Star Wars Asciimation 服务使用 telnet 协议端口 23向所有连接者流式推送 ASCII 字符动画。它不需要任何认证连接即可开始接收数据非常适合作为 TCP 客户端入门的第一个练习。第一步导入 socket 模块 import socket第二步解析服务器地址 addr_info socket.getaddrinfo(towel.blinkenlights.nl, 23) addr addr_info[0][-1]第三步创建 socket 并连接 s socket.socket() s.connect(addr)第四步循环接收并打印数据 while True: ... data s.recv(500) ... print(str(data, utf8), end) ...当这个循环开始执行动画就会一帧帧地在终端上播放出来按Ctrl-C即可中断。这段代码演示了 TCP 客户端的完整四步流程解析地址 → 创建 socket → connect → 循环 recv。几个值得注意的细节s.recv(500)指定每次最多读取 500 字节——这是缓冲区上限实际返回的字节数可能更少因此循环不断调用直到服务端关闭连接recv返回的是bytes对象需要用str(data, utf8)解码为文本end避免 print 自动换行破坏动画帧这段代码同样可以在 PC 上的标准 Python 中运行MicroPython 的 socket API 与 CPython 高度兼容非常适合在电脑上先调试通网络服务再移植到开发板。从源码看extmod/modsocket.c 中socket_recv会先检查 socket 是否已绑定网卡未连接时抛ENOTCONN随后调用网卡协议层的recv实现并将返回的字节填充到vstr中构造 bytes 对象返回若对端关闭连接返回 0则返回空 bytes。实战二HTTP GET 请求——向 Web 服务器下载网页HTTP 协议运行在 80 端口与 telnet 的连上就收不同客户端必须先发送一个GET请求指明要获取的页面路径服务器才会返回内容。下面的函数封装了完整的 HTTP 下载流程def http_get(url): import socket _, _, host, path url.split(/, 3) addr socket.getaddrinfo(host, 80)[0][-1] s socket.socket() s.connect(addr) s.send(bytes(GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n % (path, host), utf8)) while True: data s.recv(100) if data: print(str(data, utf8), end) else: break s.close()调用方式 http_get(http://micropython.org/ks/test.html)执行后网页 HTML 会被逐块打印到控制台。逐行拆解这个函数步骤代码作用解析 URL_, _, host, path url.split(/, 3)把http://micropython.org/ks/test.html拆成 host 与路径。split(/, 3)按斜杠最多切 3 次跳过http:与空串得到host micropython.org、path ks/test.html解析地址addr socket.getaddrinfo(host, 80)[0][-1]解析主机名到(ip, 80)地址对建立连接s.connect(addr)TCP 三次握手发送请求s.send(bytes(GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n ...))构造 HTTP/1.0 GET 请求报文。\r\n是 HTTP 的行结束符末尾空行表示请求头结束Host头用于虚拟主机接收响应while True: data s.recv(100)分块读取响应当recv返回空服务端关闭连接时退出循环释放资源s.close()显式关闭 socket注意 HTTP 报文格式请求行GET /path HTTP/1.0、请求头Host: hostname以及请求头与正文之间必须有一个空行\r\n\r\n这是 HTTP 规范要求、极易遗漏的细节。bytes(..., utf8)将字符串编码为字节流发送。http_get是一次性函数如果你要复用连接发送/接收多次数据应使用s.sendall(data)保证全部字节发送完毕配合s.read()/s.readline()等流式方法这些方法在 MicroPython 中由 stream 接口直接提供见 extmod/modsocket.c 中 socket 的方法表read/readline/write直接映射到通用 stream 实现。实战三HTTP 服务器——让 ESP8266 成为 Web 服务器现在把角色反转让 ESP8266 充当服务器向浏览器提供页面。下面的代码创建一个简单的 HTTP 服务器页面是一张展示所有 GPIO 引脚电平状态的表格import machine pins [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)] html !DOCTYPE html html head titleESP8266 Pins/title /head body h1ESP8266 Pins/h1 table border1 trthPin/ththValue/th/tr %s /table /body /html import socket addr socket.getaddrinfo(0.0.0.0, 80)[0][-1] s socket.socket() s.bind(addr) s.listen(1) print(listening on, addr) while True: cl, addr s.accept() print(client connected from, addr) cl_file cl.makefile(rwb, 0) while True: line cl_file.readline() if not line or line b\r\n: break rows [trtd%s/tdtd%d/td/tr % (str(p), p.value()) for p in pins] response html % \n.join(rows) cl.send(HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n) cl.send(response) cl.close()这个例子是标准的 TCP 服务器四步流程bind → listen → accept → 循环处理。服务器核心要素分析绑定通配地址socket.getaddrinfo(0.0.0.0, 80)让服务器监听所有网络接口无论板子从路由器获得什么 IP客户端都能访问bind(addr)将 socket 绑定到该地址与 80 端口。注意在 ESP8266 上绑定 80 端口前应确认没有其他服务占用该端口。监听队列s.listen(1)允许 1 个未处理的连接请求排队多余的连接会被拒绝。源码中socket_listenextmod/modsocket.c会先将负的 backlog 钳制为 0。accept 返回连接s.accept()阻塞等待客户端连接返回(cl, addr)二元组——cl是专用于该连接的新 socket 对象addr是客户端地址源码见 extmod/modsocket.c新 socket 继承父 socket 的地址族、类型与协议。读取请求头cl.makefile(rwb, 0)创建与 socket 关联的文件对象rwb表示可读可写二进制模式0表示无缓冲MicroPython 会忽略 buffering 参数并视为 0。readline()逐行读取 HTTP 请求头遇到空行b\r\n即请求头结束——服务器不必解析请求内容只需读出并丢弃请求头即可返回响应。构造并发送响应先用p.value()实时读取每个 GPIO 引脚电平生成 HTML 表格行再拼接完整页面。响应报文由状态行HTTP/1.0 200 OK、响应头Content-type: text/html、空行与正文组成。关闭连接处理完一个请求后cl.close()关闭该连接注意makefile()返回的文件对象被关闭时会同时关闭底层 socketsocket 模块文档 中的明确提示。浏览器访问http://ESP8266的IP/即可看到带引脚的实时状态表格。在 ESP8266 上运行 HTTP 服务器时应留意内存与功耗请求频率高时可以在循环中加入machine.idle()或适当延时避免长时间满负荷运行。服务器示例的测试验证仓库中 tests/multi_net/tcp_data.py 是一个双实例 TCP 服务器/客户端对测用例可视为本示例的精简版本服务器端bind → listen → accept → recv → send客户端connect → send → recv完整覆盖了上述 API 的调用链是理解 MicroPython 网络栈行为的绝佳参考。进阶TCP 编程的可靠性要点1. 用流式接口代替原生方法MicroPython 的 socket 对象本身就是一个流对象read()、readline()、write()直接可用。官方推荐用write()替代sendall()阻塞模式下二者都保证无短写非阻塞模式下sendall()行为未定义而write()会返回实际写入字节数用read()替代recv()可享受无短读语义。这在处理 HTTP 这类需要完整读取一行/一段数据的协议时尤其方便。2. 超时与非阻塞settimeout(value)设置阻塞操作超时单位秒非零值超时后抛OSError0切换为非阻塞模式None恢复阻塞模式。setblocking(flag)是其快捷方式setblocking(True)等价settimeout(None)setblocking(False)等价settimeout(0)源码见 extmod/modsocket.c超时值在内部换算为毫秒存储。更可移植的等待方案是使用select.poll()它可以同时轮询多个流对象poller.poll(1000)以毫秒为单位等待就绪事件从而优雅地实现非阻塞 超时语义。ESP8266 上如果某个网络操作卡死超时机制是保证程序健壮性的关键。3. 异常处理MicroPython 没有 CPython 的socket.error与socket.gaierror一律抛OSError。getaddrinfo的解析错误用负数错误码表示与 errno 的正数错误码分属不同命名空间。因此解析域名时用except OSError捕获tests/net_inet/getaddrinfo.py 展示了这一模式通用的except OSError:写法在 MicroPython 与 CPython 下都能工作保持代码双端兼容。4. 资源管理socket 对象在垃圾回收时会自动关闭但官方明确建议用完后立即显式close()尤其在服务器场景每个accept()产生一个新 socket若不关闭会迅速耗尽内存。MicroPython 的 socket 对象带有析构器mp_obj_malloc_with_finaliser见 extmod/modsocket.c但依赖 GC 释放资源在内存紧张的 ESP8266 上并不明智。5. 复用地址服务器重启时可能遇到address in use错误可在bind前执行s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)允许地址复用——tests/multi_net/tcp_data.py 的服务器端正是这么做的这也是嵌入式 Web 服务器开发中的常见惯例。总结场景核心 API 流程关键点TCP 客户端telnet 拉流getaddrinfo → socket() → connect → recv 循环无需认证连上即收Ctrl-C中断HTTP 客户端网页下载getaddrinfo → socket → connect → send(GET) → recv 循环HTTP 报文格式请求行 Host 头 空行HTTP 服务器GPIO 看板getaddrinfo(0.0.0.0) → socket → bind → listen → accept → 收发 → close请求头以空行结束每个连接独立 socket 需关闭通过这三个循序渐进的项目你已经掌握了 MicroPython 在 ESP8266 上使用 TCP socket 完成下载数据与提供服务两种角色的全部要点地址解析用getaddrinfo、客户端记住解析-连接-收发三步、服务器记住绑定-监听-接受-关闭四步、始终显式关闭 socket。这套模式适用于 HTTP、MQTT、WebSocket、SSH 等几乎所有基于 TCP 的协议是进一步开发 ESP8266 物联网应用的基石。建议接着阅读 ESP8266 教程索引 中的 文件系统 与 引脚控制 章节将网络能力与存储、GPIO 结合构建更完整的嵌入式应用。赞分享嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载相关推荐OfficeCLI 扩展图表实战指南用 cx:chart 家族一键生成 Waterfall、Treemap、Histogram 与 ParetoOfficeCLI 扩展图表实战指南用 cx:chart 家族一键生成 Waterfall、Treemap、Histogram 与 Pareto 导读 Exc人工智能AI 应用AI 技能CLIMCP 服务30分钟上手Odin网络编程从TCP客户端到HTTP服务器实战指南30分钟上手Odin网络编程从TCP客户端到HTTP服务器实战指南 你是否还在为网络编程的复杂概念而头疼是否想快速构建可靠的网络应用却不知从何下手本文将带编程语言编译器语言运行时RIOT gcoap 示例实战指南基于 CoAP 的 IoT 网络客户端与服务器RIOT gcoap 示例实战指南基于 CoAP 的 IoT 网络客户端与服务器 导读 本文围绕 RIOT 官方示例 examples/networking/物联网嵌入式操作系统实时系统上一篇 Review RTK下一篇CloudBeaver 与 DBeaver 对比分析选择最适合你的数据库工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考