Microdot 搭建 Web 服务

罗大富 BigRich大约 12 分钟ESP32Python

这节课我们来学习,在 ESP32 上搭建一个 Web 服务,并通过这个服务实现点灯的效果。

实验原理

1. Socket 套接字

说到 Socket,就不得不提两个计算机专业词汇最糟糕的翻译:鲁棒性(Robustness)套接字(Socket),翻译之后与没有翻译的效果一样,依然看不懂什么意思。

当涉及到网络通信时,Socket 是一个常见的概念。它是在计算机网络中实现通信的一种抽象概念或编程接口。通过 Socket,不同计算机之间可以建立连接并进行数据交换。

Socket 可以看作是一种通信端点,它使用 IP 地址和端口号来标识不同的设备和应用程序。每个 Socket 都与一个特定的协议相关联,例如 TCP 或 UDP,用于在网络上进行数据传输。

Socket 翻译过来其实就是插座的意思,在台湾和香港被翻译成 网络插座,这种翻译方式其实也很好的反映了 Socket 通信的特点。

Socket 是通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议(通常是 TCP 或 UDP),本地主机的IP地址,本地进程的协议端口,远地主机的 IP 地址,远地进程的协议端口。

从上图可以看到,建立 Socket 通信需要一个服务器端和一个客户端。对于客户端,则需要知道电脑端的 IP 和端口即可建立连接。(端口可以自定义,范围在 0~65535,注意不占用常用的80等端口即可。)

下面是 Socket 的一些关键概念:

  • IP地址:在计算机网络中,每个设备都有一个唯一的 IP 地址,用于标识设备的位置。IP 地址由一系列数字组成,例如 IPv4 地址是由四个十进制数(0-255)组成,中间用点分隔,如 192.168.0.1。

  • 端口号:端口号用于标识一个特定的应用程序或服务,使数据可以传输到正确的目的地。端口号是一个数字,范围从 0 到 65535。0 到 1023 的端口号是为一些特定的服务保留的,例如HTTP的端口号是80,HTTPS的端口号是443。

  • Socket 类型:在 Socket 编程中,有两种常见的套接字类型:Stream Socket(流套接字)Datagram Socket(数据报套接字)

    1. Stream Socket(流套接字) 使用 TCP 协议,提供可靠的、面向连接的通信,确保数据的可靠性和按顺序的传输。
    2. Datagram Socket(数据报套接字) 使用 UDP 协议,提供无连接的通信,适用于实时性要求高的应用,如音视频传输。
  • 客户端和服务器:在 Socket 通信中,通常有两个主要角色:客户端服务器

    1. 客户端 是发起连接请求的一方,通常是一个应用程序或设备。
    2. 服务器是提供服务的一方,它监听指定的端口号,并等待客户端的连接请求。

通过 Socket,客户端和服务器可以建立连接,并通过发送和接收数据进行通信。客户端可以向服务器发送请求,并接收服务器的响应。服务器可以接收客户端的请求,并向客户端发送响应。

在实际的 Socket 编程中,使用不同编程语言提供的 Socket API,如 C/C++ 的 socket 库、Python 的 socket 模块等,来创建、连接、发送和接收数据。这些 API 提供了一组函数和方法,开发者可以使用这些函数和方法来实现网络通信的各个方面。

总而言之,Socket 是一种用于实现网络通信的抽象概念,通过使用 IP 地址和端口号,不同计算机之间的应用程序可以建立连接,并通过发送和接收数据进行通信。

所以,socket 的出现只是可以更方便的使用 TCP/IP 协议栈而已,简单理解就是其对 TCP/IP 进行了抽象,形成了几个最基本的函数接口。比如 create,listen,accept,connect,read 和 write 等等。以下是通讯流程:

以上的内容,简单来说就是如果用户面向应用来说,那么 ESP32 只需要知道通讯协议是 TCP 或 UDP、服务器的 IP 和端口号这 3 个信息,即可向服务器发起连接和发送信息。

2. 前端

我们刚刚也说了 ESP32 可以作为服务端,也就是说把 ESP32 作为一个服务器,实际上呢,这种方式并不常用,因为 ESP32 的性能与一般的云服务器完全没有可比性,但是也许有一些特殊的情况,导致我们不得不使用 ESP32 作为服务器的时候。

我们平时用到的 HTTP 服务有很多,比如我们现在打开一个网站,看到的这个页面,这个页面中的内容其实也是代码编写出来的,我们可以点击键盘的 F12,打开 开发者工具,查看页面元素,就可以看到我们页面的源代码了。

我们需要明白搭建一个 Web 服务一般都会包括前端和后端,如果你只是搭建一个 API 服务的话,前端就可以不涉及。

前端是指在 Web 开发中负责实现用户界面和用户交互的部分。前端开发涉及使用 HTML、CSS 和 JavaScript 等技术来构建网页,并与用户进行互动。当涉及到前端开发时,HTML、CSS 和 JavaScript 是三种主要的技术,它们共同构成了现代 Web 页面的基础。

  1. HTML(超文本标记语言):

    • HTML 是一种标记语言,用于定义网页的结构和内容。
    • 使用 HTML 标签,可以创建网页的各种元素,如标题、段落、图像、链接等。
    • HTML 使用标签(例如 div、p、img)和属性(例如class、id、src)来描述页面元素的结构和属性。
  2. CSS(层叠样式表):

    • CSS 用于描述网页的样式和外观。
    • 使用 CSS 选择器和属性,可以为 HTML 元素指定样式,如字体、颜色、布局等。
    • CSS 样式可以直接嵌入在 HTML 中,也可以在外部 CSS 文件中定义,并通过链接引入到 HTML 中。
  3. JavaScript:

    • JavaScript 是一种脚本语言,用于为网页添加交互和动态功能。
    • JavaScript 可以通过操作 HTML 元素、处理用户输入、发送网络请求、处理数据等来实现各种功能。
    • JavaScript 可以直接嵌入在 HTML 中,也可以作为外部脚本文件链接到 HTML 中。

这三种技术相互配合,实现了现代 Web 页面的开发和呈现,HTML 定义了网页的结构和内容,CSS定义了网页的样式和外观,JavaScript 为网页添加了交互和动态功能。

通过使用 HTML、CSS 和 JavaScript,前端开发者可以创建吸引人、交互式的 Web 页面和应用程序。HTML 负责构建页面结构,CSS 负责设计页面样式,JavaScript 负责处理用户行为和动态交互。这三种技术共同构建了现代 Web 开发的基础。

硬件电路设计

由于 ESP32 内置 WiFi 功能,所以直接在开发板上使用即可,无需额外连接。

软件程序设计

MicroPython 目前有两个 Web 框架:microWebSrvMicrodotopen in new window

由于 microWebSrv 不支持 ESP8266,所以,我们选择学习如何使用 Microdotopen in new window

Microdot 是一个受 Flask 启发的简约 Python Web 框架,被设计为轻量级的 Web 服务器,适用于资源受限的嵌入式设备,例如 ESP32,ESP8266。它只需要很少的 RAM 和存储空间,并且具有较低的 CPU 消耗.

你可以通过定义多个路由来处理不同的 URL 请求。每个路由由 URL 路径和相应的处理函数组成。当收到匹配的请求时,服务器将调用相应的处理函数。Microdot 还支持静态文件服务,可以轻松地将静态文件(如 HTML、CSS、JavaScript、图像等)提供给客户端。你只需要指定一个目录,服务器将自动处理静态文件的请求。集成了简单的模板引擎,使您可以轻松地生成动态的HTML响应。您可以在 HTML 文件中定义占位符,然后使用模板引擎将占位符替换为实际的值。

Microdot 支持 HTTP 的 GET 和 POST 请求。您可以通过定义相应的路由和处理函数来处理不同类型的请求。

下面是一个简单的介绍如何使用 Microdot:

首先,我们需要在 Microdot 的 GitHub 仓库下载对应的文件 microdot.pyopen in new window,或者,在我们的 资料包 中的 3.开发工具 也能找到 Microdot 的源代码,并把该代码复制到 Micropython 设备中的 libs 目录下

接着需要创建 Microdot 应用,导入 Microdot 模块,并创建一个 Microdot 应用对象

from libs.microdot import Microdot

app = Microdot()

在 Microdot 中,使用路由来指定 URL 与视图函数之间的关系。视图函数是处理请求并生成响应的函数。可以使用 @app.route 装饰器来定义路由,例如:

@app.route('/')
def home():
    return 'Hello, MicroDot!'

在上述示例中,@app.route('/')定义了一个根路由,它对应于网站的根 URL。home()函数是视图函数,当访问根 URL 时,该函数将被执行。在此示例中,它简单地返回一个字符串作为响应。

最后就是运行这个应用,只需要在 Python 文件的末尾,添加一个简单的代码块:

if __name__ == '__main__':
    app.run()

这样我们就会启动 Microdot 开发服务器,并且监听默认的 5000 端口。你可以在手机端或者浏览器中访问 http://ESP32的局域网IP:5000 来查看应用程序的响应

您可以根据需要在应用程序中添加更多的路由和视图函数。通过定义不同的路由和对应的视图函数,您可以实现不同的页面和功能。

Microdot 还提供了许多功能和扩展,例如模板引擎、表单处理、数据库集成等。您可以根据需求选择适合您的扩展来增强您的应用程序。

当然,Microdot 的内容不止这些,还有很多功能可以参考 Microdot 使用文档open in new window

所以,我们可以通过以下方式实现手机 LED 亮灭的效果:

注意

这段代码并不规范!目的是为了让初学者快速的搭建一个 Web 服务,在生产环境中,有更多的协议和规范,来让你实现手机控制 LED 亮灭的效果。

from machine import Pin

from common.wifi import wifi_connect
from libs.microdot import Microdot


led_pin = Pin(2, Pin.OUT)


# 定义 WIFI 的账号密码
ssid = 'GeeksMan'
password = '123456qq.'

# 连接 WiFi
wifi_connect(ssid, password)

app = Microdot()

htmldoc = '''<!DOCTYPE html>
<html>
    <head>
        <title>ESP32 MicroPython Microdot Web 服务</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>
        <div>
            <h1>ESP32 MicroPython Microdot Web 服务</h1>
            <p>你好,Microdot!</p>
            <p><a href="/shutdown">关闭服务</a></p>
            <p><a href="/led">开关灯</a></p>
        </div>
    </body>
</html>
'''


@app.route('/')
def hello(request):
    return htmldoc, 200, {'Content-Type': 'text/html'}


@app.route('/shutdown')
def shutdown(request):
    request.app.shutdown()
    return 'The server is shutting down...'

@app.route('/led')
def led(request):
    led_pin.value(not led_pin.value())
    return htmldoc, 200, {'Content-Type': 'text/html'}


app.run(host='0.0.0.0', port=5000, debug=True)

这些只是一些简单的 Web 服务的搭建,如果你真的想要学习 Python Web 开发的话,可以考虑学习 Django/Flask/FastAPI,首推 Django,因为 Django 自带后端管理系统,可以让你少写一点前端的代码,并且实现数据可视化管理操作。

Web 开发模式

目前主流 Web 开发模式有两种,分别是:

  1. 基于服务端渲染的传统 Web 开发模式,服务器发送给客户端的 HTML 页面,是在服务器通过字符串拼接,动态生成的。不需要使用 Ajax、Axios 这样的网络请求库额外请求页面的数据。优点是前端耗时少。因为服务器端负责动态生成 html 内容,浏览器只需要直接渲染页面即可,有利于 SEO。因为服务器端响应的是完整的 html 页面内容,所有爬虫更容易爬取获得信息,更有利于 SEO。缺点是占用服务器端资源。因为服务器端完成 HTML 页面内容的拼接,如果请求较多,给服务器造成一定的访问压力,不利于前后端分离,开发效率低。使用服务器渲染,无法进行分工合作,尤其对于前端复杂度高的项目,不利于项目高效开发。

  2. 基于前后端分离的新型 Web 开发模式,依赖于 Ajax、Axios、fetch 网络请求技术的广泛应用。就是后端只负责提供 API 接口,前端使用网络请求调用接口的开发模式。优点是开发体验好。前端专注于 UI 页面开发,后端专注于 API 的开发,且前端有更多的选择性。用户体验好。Ajax 技术的广泛应用,极大的提高了用户体验,可以轻松实现页面局部刷新。减轻了服务器端的渲染压力。因为页面最终是在每个用户的浏览器中生成的。不利于 SEO。因为完整的 html 页面内容在客户端动态拼接完成,爬虫对无法爬取页面有效信息。(解决方案:利用 Vue、React 等前端框架的 SSR 技术能够很好的解决 SEO 问题)。

当前我们这段代码使用的就是第一种服务端渲染的前后端不分离的开发模式,如果你只是想开发一些简单的小项目,使用这种方式是没有问题的,但是,项目复杂度高一点之后,就会导致后期维护困难。因此,如果你只是想要做一些小项目,可以选择服务器渲染,在 Python 中可以使用 Flask 框架,如果你想做一些复杂度高一点的项目,并且前后端分离,可以选择使用 Django 与 Djanog RestFramework 插件,前端使用 Vue/React。

上次编辑于:
贡献者: Luo