1

我在 Raspberry Pi 上编写了一个 python 脚本,它控制着一个大型且有些复杂的硬件。目前使用界面是python控制台。我运行 python 程序,并且可以从控制台输入命令input("> ")

现在我想为这个程序添加一个网络界面,我正在尝试找出正确的方法来做到这一点。我已经在flask中编写了一个基本的web UI,但是我还没有找到一个连接flask界面和主脚本的好方法。因为服务器控制单个硬件,所以主对象(处理硬件控制)只实例化一次。此外,每次运行脚本(每次创建主对象时)都必须进行重要的硬件配置。

Flask 似乎为每个客户端会话创建一个新线程,并且只在该会话中保留变量。如何将烧瓶事件(即网络用户按下按钮)链接到主对象中的方法?

我是否使用了错误的工具来完成这项工作?什么是正确的工具?这样做的正确方法是什么?或者,什么是jank方式来做到这一点?

编辑:链接的问题是相似的,并引导我找到下面的答案,但他们真的没有回答这个问题,只是指向一些解决该特定示例的代码。我认为下面的答案更有帮助。(当然我有点偏见;我写的)

我找到了解决方案,所以我会在这里分享。(我想我无法回答自己的问题?)

Flask Web App 系统(以及所有 WSGI Web 应用程序?)依赖于 Web 应用程序可以在全新环境中执行的原则,而无需在创建时传递对象。我想这对Web Apps来说是有意义的,但它给Web UI增加了很多烦人的复杂性,也就是说,Web 界面专门用于连接更大程序的单个实例。作为硬件/解决方案工程师,我倾向于需要一个 Web UI 来控制单个硬件。如果为此目的有比烧瓶更好的东西,发表评论。但是烧瓶很好,我现在知道它可以用于此目的。

Flask Web 应用程序并非旨在自己完成“繁重的工作”。它们保持非常有限的状态(即每个请求都会触发一个新的上下文),并且如前所述,不能将引用传递给其他对象。在适当的Web 应用程序中,全栈开发人员会将 Flask 连接到数据库服务器和其他此类 WebDev-y 系统。为了控制硬件,我们的目标是在另一个 python 进程(很可能是一个单独执行的进程)中触发一些任意方法的执行。

在 python 中,实现此执行的一种便捷方法是multiprocessing.managers模块。管理器是一种工具,可让您轻松构建代理,它可以跨进程链接对象。如果您有一个对象bar = Bar(),您可以生成一个<AutoProxy[get_bar]>代理,它允许您bar从远处操纵原始对象。远处可以在子进程中,在互联网上的另一台计算机上。这是一个例子。

服务器.py:

import multiprocessing.managers as m
import logging
logger = logging.getLogger()

class Bar: #First we setup a dummy class for this example.
    def __init__(self):
        self.text = ""
    def read(self):
        return str(self.text)
    def write(self, string):
        self.text = str(string)
        logger.error("Wrote!")
        logger.error(string)

bar = Bar() #On the server side we create an instance: this is the object we want to share to other processes.

m.BaseManager.register('get_bar', callable=lambda:bar) #then we register a 'get' function in the manager,
# to retrieve our object from afar. the lambda:bar is just shorthand for a function that returns the bar object.
manager = m.BaseManager(address=('', 50000), authkey=b'abc') #Then we setup the server on port 50000, with a password.
server = manager.get_server() 
server.serve_forever() #Then we start the server!

客户端.py:

import multiprocessing.managers as m
import logging

logger = logging.getLogger()

m.BaseManager.register('get_bar') #We register this so that the Manager knows it's a valid method
manager = m.BaseManager(address=('', 50000), authkey=b'abc') #Then we setup the server connection
manager.connect() #and connect!
bar = manager.get_bar() # now we can use our 'get' method to retrieve a Proxy of the object.

所以这里有一些有趣的事情需要注意。首先,我们可以从任意多的客户端获取 get_bar(),它们都会指向同一个bar. 其次,我们可以从客户端调用 bar、read() 和 write() 中的方法,而无需Bar手头的类。挺整洁的。

那么如何使用这个呢?如果你有一个支持控制台的程序,首先把它分成两部分,控制台和它控制的功能。将该功能封装在少数几个对象中,这些对象共同构成应用程序的实例。在上面进行修改server.py以实例化这些对象,并使用管理器中的方法将它们托管出来get。然后调整您的控制台界面以连接client.py并使用代理而不是实际对象。最后,设置一个烧瓶应用程序,该应用程序也连接到服务器并提供 Web 界面。

现在您是真正的 Web 开发人员了!RIP。

4

0 回答 0