Perspective Broker 简介

简介

假设你控制着电线的两端:你有两个需要相互通信的程序,你可以使用任何你想要的协议。如果你可以从需要相互调用方法的对象的角度来思考你的问题,那么你很可能可以使用 Twisted 的 Perspective Broker 协议,而不是试图将你的需求塞进像 HTTP 这样的东西,或者实现另一种 RPC 机制 [1]

Perspective Broker 系统(简称“PB”,引发了许多与三明治相关的双关语)基于几个核心概念

  • 序列化:将相当任意的对象和类型转换为字节块,通过电线发送它们,然后在另一端重新构建它们。通过仔细跟踪对象 ID,序列化对象可以包含对其他对象的引用,并且远程副本仍然有用。

  • 远程方法调用:对本地对象执行某些操作,并导致在远程对象上运行方法。本地对象称为 RemoteReference,你通过运行它的 .callRemote 方法来“执行某些操作”。

本文档将包含几个示例,这些示例在您弄清楚是怎么回事后(希望)会显得冗余和啰嗦。首先,许多代码将被简单地标记为“魔法”:不要担心这些部分是如何工作的。稍后将更详细地解释。

对象路线图

首先,以下是 PB 中涉及的主要类、接口和函数,以及它们定义所在文件的链接(所有这些文件都在 twisted/ 下,当然)。不要担心现在理解它们的功能:通过它们的交互来理解它们比逐个解释它们更容易。

其他在某些时候涉及的类

  • RemoteReferencespread/pb.py

  • pb.Rootspread/pb.py,实际上定义为 twisted.spread.flavors.Rootspread/flavors.py

  • pb.Referenceablespread/pb.py,实际上定义为 twisted.spread.flavors.Referenceablespread/flavors.py

当您开始关注授权和安全时涉及的类和接口

子类化和实现

从技术上讲,您可以对任何您想要的东西进行子类化,但从技术上讲,您也可以编写一个全新的框架,这只会浪费很多时间。了解哪些类对子类化有用,或者哪些接口需要实现,是成功使用 PB(以及所有 Twisted)的关键知识之一。以下是一些入门提示

  • pb.Rootpb.Referenceable:您将对它们进行子类化以创建可远程引用的对象(即,您可以通过 PB 远程调用其方法的对象)。您不需要更改任何现有行为,只需继承所有行为并添加您想要导出的可远程访问方法。

  • pb.Avatar:当您开始使用 PB 进行授权编程时,您将对它进行子类化。这是一个 IPerspective 的实现者。

  • ICredentialsChecker:如果您想对用户进行身份验证,使其与某种数据存储进行匹配,请实现它:例如,LDAP 数据库、RDBMS 等。twisted.cred.checkers 中已经有一些针对各种后端的实现。

可以远程调用的内容

在撰写本文时,有三种可以通过 RemoteReference 对象远程访问的对象“风格”。每种风格都有一个规则,用于将 callRemote 消息转换为服务器上的本地方法调用。为了使用其中一种“风格”,请对它们进行子类化,并使用适当的前缀命名您发布的方法。

  • twisted.spread.pb.IPerspective 实现者

    这是我们处理的第一个接口。它是您 PB 应用程序的“视角”。视角有点特殊,因为它们通常是给定用户在您的应用程序中可以访问的第一个对象(在他们登录之后)。用户应该只收到对他们自己视角的引用。PB 尽其所能努力验证,任何可以直接在视角上调用的方法都代表着该视角所代表的用户进行调用。(具有对“代表”的特殊要求的服务,例如能够拥有另一个玩家化身的模拟,是通过提供对另一个用户视角的间接访问来实现的。)

    视角通常不会序列化为远程引用,因此不要直接返回 IPerspective 实现者。

    大多数人想要实现 IPerspective 的方式是通过继承 pb.Avatar。pb.Avatar 实例上远程可访问的方法以 perspective_ 为前缀命名。

  • twisted.spread.pb.Referenceable

    可引用对象是最简单的 PB 对象类型。您可以调用它们的方法,并从方法中返回它们,以提供对其他对象方法的访问。

    但是,当在可引用对象上调用方法时,无法确定是谁调用了它。

    可引用对象上远程可访问的方法以 remote_ 为前缀命名。

  • twisted.spread.pb.Viewable

    可查看对象是远程可引用对象,它们有额外的要求,即必须能够确定是谁在调用它们。可查看对象的远程方法的参数列表被修改,以包含表示调用用户的 Perspective。

    可查看对象上远程可访问的方法以 view_ 为前缀命名。

可以远程复制的内容

除了返回可以调用远程方法的对象之外,您还可以返回本地对象的结构化副本。

有两种基本类型允许远程复制对象。同样,您可以通过继承它们来使用它们。为了指定在序列化时要复制的状态,您可以使用 Python 默认的 __getstate__ 或该类型的专门方法调用。

  • twisted.spread.pb.Copyable

    这是可以复制的最简单的对象类型。每次从方法中返回此对象或将其作为参数传递时,它都会被序列化和反序列化。

    Copyable 提供了一个可以覆盖的方法,getStateToCopyFor(perspective),它允许您决定对象对于请求它的 Perspective 的外观。perspective 参数将是传递参数或返回 Copyable 类实例结果的 Perspective。

    出于安全原因,为了允许特定的 Copyable 类实际被复制,您必须为该 Copyable 子类声明一个 RemoteCopy 处理程序。最简单的方法是在同一个模块中声明两者,如下所示

    from twisted.spread import flavors
    class Foo(flavors.Copyable):
        pass
    class RemoteFoo(flavors.RemoteCopy):
        pass
    flavors.setUnjellyableForClass(Foo, RemoteFoo)
    

    在这种情况下,每次在对等体之间复制 Foo 时,都会实例化一个 RemoteFoo 并用 Foo 的状态填充它。如果您不这样做,PB 会抱怨存在安全违规,并且它可能会关闭连接。

  • twisted.spread.pb.Cacheable

    让我先说一句警告:Cacheable 可能很难理解。如果您没有使用某种远程方法调用的实际应用程序的经验,它的动机可能不清楚。一旦您理解了为什么需要它,它做了什么可能看起来很简单明了,但如果您对此感到困惑,就忘记它,以后再回来。在完全不了解 Cacheable 的情况下使用 PB 是可能的。

    Cacheable 是一种类型,它被设计为仅在必要时复制,并在对它进行更改时动态更新。当作为参数或返回值传递时,如果在连接的另一端存在 Cacheable,它将通过 ID 引用,而不是复制。

    Cacheable 被设计为最大程度地减少在多个服务器之间复制对象时发生的错误,尤其是与拥有陈旧信息相关的错误。为了做到这一点,Cacheable 会自动注册观察者并原子地查询状态,并将它们组合在一起。您可以覆盖方法 getStateToCacheAndObserveFor(self, perspective, observer),以指定如何存储和更新您的观察者。

    类似于 getStateToCopyForgetStateToCacheAndObserveFor 会传递一个 Perspective。它还会传递一个 observer,它是一个对“秘密”第四种可引用类型 RemoteCache 的远程引用。

    一个 RemoteCache 只是表示连接另一端 Cacheable 的对象。它使用与 RemoteCopy 相同的方法注册,如上所述。但是,RemoteCache 与众不同,因为它将被其对等体引用。它充当可引用对象,其中所有以 observe_ 为前缀的方法都可以在远程调用。建议您的对象维护一个观察者列表(注意:库对它的支持即将推出!),并在 Cacheable 以对客户端可见的方式更改时使用 callRemote 更新它们。

    最后,当来自给定 Perspective 对 Cacheable 的所有引用都丢失时,stoppedObserving(perspective, observer) 将在 Cacheable 上调用,使用与最初调用 getStateToCacheAndObserveFor 相同的 Perspective/观察者对。任何清理远程调用都可以在那里进行,以及从观察者对象之前所在的任何列表中删除观察者对象。对该观察者对象的任何进一步调用都将无效。

脚注