3

我有一个 Pyro4 分布式系统,有多个客户端连接到单个服务器。这些客户端连接到一个远程对象,该对象可能会在系统中分配一些资源(在我的例子中是虚拟设备)。

一旦客户端断开连接(假设是因为崩溃),我需要释放这些资源。检测特定客户端已与特定对象断开连接的正确方法是什么?

我尝试了不同的东西:

  • 覆盖Daemon.clientDisconnected方法。我connection从这个方法中得到一个参数。但我无法将其与对象相关联,因为我无法访问该连接所指的远程对象。
  • 使用Pyro4.current_contextDaemon.clientDisconnected. 这不起作用,因为这是一个线程本地对象。这样,如果我连接的客户端多于池中的线程,我就会得到重复的上下文。
  • 在 Pyro4 项目可用的“usersession”示例中使用Proxy._pyroAnnotationsas 对我没有帮助,因为我再次从Pyro4.core.current_context.annotations属性中获取注释,它在Daemon.clientDisconnected调用时显示错误的注释(我想是由于线程相关问题)。
  • 在远程类中使用instance_mode="session"__del__方法(因为每个客户端都有一个单独的类实例,因此一旦客户端断开连接,该实例就应该被销毁)。但这依赖于__del__方法,正如一些 Python 程序员会指出的那样,该方法存在一些问题。

我添加了我当前的解决方案作为答案,但我真的很想知道 Pyro4 是否有更优雅的方法,因为这种情况是网络编程中的一种循环模式。

4

2 回答 2

2

Pyro 4.63 可能会对此提供一些内置支持,以使其更容易执行。你可以在这里阅读它http://pyro4.readthedocs.io/en/latest/tipstricks.html#automatically-freeing-resources-when-client-connection-gets-closed 如果你克隆当前的主人,请尝试一下GitHub。也许您可以看一下,看看这是否会使您的用例更简单?

于 2017-09-28T22:01:49.927 回答
1

Proxy._pyroHandshake在客户端使用该属性作为客户端 ID 并覆盖Daemon.validateHandshakeand Daemon.clientDisconnected。这样,在每个新连接上,我都会将握手数据(每个客户端唯一)映射到连接。但我真的很想知道在 Pyro4 中是否有一种优雅的方法可以做到这一点,这是在网络编程中经常出现的模式。

请注意,除了使用 Proxy 作为 Client 的属性之外,Client 还可以扩展 Pyro4.Proxy 并使用 _pyroAnnotations 将客户端 ID 发送到所有远程调用。

class Client:

    def __init__(self):

        self._client_id = uuid.uuid4()
        self._proxy = Pyro4.Proxy("PYRO:server@127.0.0.1")
        self._proxy._pyroHandshake = self._client_id
        self._proxy._pyroBind()

    def allocate_resource(self, resource_name):
        self._proxy.allocate_resource(self._client_id, resource_name)


class Server:

    def __init__(self):

        self._client_id_by_connection = {}
        self._resources_by_client_id = {}

    def client_connected(self, connection, client_id):

        self._client_id_by_connection[client_id] = connection
        self._resources_by_client_id[client_id] = []

    def client_disconnected(self, connection):

        client_id = self._client_id_by_connection[connection]

        for resource in self._resources_by_client_id[client_id]
            resource.free()

    @Pyro4.expose
    def allocate_resource(self, client_id, resource_name)

        new_resource = Resource(resource_name)
        self._resources_by_client_id[client_id].append(new_resource)

server = Server()
daemon.register(server, objectId="server")
daemon.clientDisconnect = server.client_disconnected
daemon.validateHandshake = server.client_connected
daemon.requestLoop()
于 2017-08-25T13:36:51.457 回答