使所有属性和方法可用于 Python 中的套接字服务器

Making all attributes and methods available for a socket server in Python

我使用 Raspberry Pi 来收集传感器数据和设置数字输出,以方便其他应用程序设置和获取我正在使用的套接字服务器的值。 但是我在寻找一种优雅的方式使所有数据在套接字服务器上可用而不必为每种数据类型编写函数时遇到了一些问题。

我想在套接字服务器上提供的一些值和方法示例:

do[2].set_low()    # set digital output 2 low
do[2].value=0      # set digital output 2 low
do[2].toggle()     # toggle digital output 2
di[0].value        # read value for digital input 0
ai[0].value        # read value for analog input 0
ai[0].average      # get the average calculated value for analog input 0
ao[4].value=255    # set analog output 4 to byte value 255
ao[4].percent=100  # set analog output 4 to 100%

我试过 eval()exec():

self.request.sendall(str.encode(str(eval('item.' + recv_string)) + '\n'))
除非我使用等号 (=),否则

eval() 有效,但由于涉及危险,我对该解决方案并不满意。 exec() 完成工作但没有 return 任何价值,也很危险。

我也试过了getattr():

recv_string = bytes.decode(self.data).lower().split(';')
values = getattr(item, recv_string[0])
self.request.sendall(str.encode(str(values[int(recv_string[1])].value) + '\n'))
                                                                ^^^^^

这适用于获取我的属性,上面的示例适用于获取我使用 getattr() 获取的属性的 value。但是我也不知道如何在 value 属性上使用 getattr()

分号(;)是用来分割传入命令的,我尝试了多种格式化命令的方式:

# unit means that I want to talk to a I/O interface module,
# and the name specified which one

unit;unit_name;get;do;1
unit;unit_name;get;do[1]
unit;unit_name;do[1].value

我可以自由选择格式,因为我也在编写使用这些命令的软件。我还没有找到满足我所有需求的好格式。

有什么建议可以编写优雅的方式来访问和 returning 上面的数据吗?最好每次向我的 I/O 端口添加新值类型或方法时都必须向套接字服务器添加新方法。

编辑:这不是公开的,只能在我的局域网上使用。

建议

使您的 API 所有方法都可以始终使用 eval:

def value_m(self, newValue=None):
    if newValue is not None:
        self.value = newValue
    return self.value

那你随时都可以做

result = str(eval(message))
self.request.sendall(str.encode(result + '\n'))

对于您的 message,我建议您将 消息 格式化为包含命令的确切语法,以便它可以 eval按原样编辑,例如

message = 'do[1].value_m()'  # read a value, alternatively...
message = 'do[1].value_m(None)' 

或写

message = 'do[1].value_m(0)'  # write a value

这将使您的消息与您的 API 保持同步变得容易,因为它们必须完全匹配,您不需要处理第二个 DSL。您真的不想在您的 IO 之上维护第二个 API。

这是一个非常简单的方案,适合家庭项目。我建议在评估中进行一些错误处理,例如:

import traceback

try:
    result = str(eval(message))
except Exception:
    result = traceback.format_exc()
self.request.sendall(str.encode(result + '\n'))

这样您的调用者将在返回的消息中收到异常回溯的打印输出。这将使错误调用的调试变得非常非常容易。

注意 如果这是面向 public 的,您不能 这样做。所有输入都必须经过清理。您将必须解析每条指令并将其与可用(和所需)命令列表进行比较,并验证所有输入的有效性和有效性范围。对于这种情况,您最好简单地使用一种用于 Web 服务的输入验证系统,这个问题受到了很多关注。