Pyro4客户端意外断开连接时释放资源

时间:2017-08-25 13:36:51

标签: python pyro4

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

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

我尝试过不同的事情:

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

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

2 个答案:

答案 0 :(得分:2)

Pyro 4.63可能会有一些内置的支持,以便更容易做到。您可以在此处阅读http://pyro4.readthedocs.io/en/latest/tipstricks.html#automatically-freeing-resources-when-client-connection-gets-closed并尝试从Github克隆当前的主服务器。也许你可以看看是否会使你的用例更简单?

答案 1 :(得分:1)

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

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

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()