当 Pyro4 客户端意外断开连接时释放资源
Releasing resources when Pyro4 client disconnects unexpectedly
我有一个 Pyro4 分布式系统,多个客户端连接到一个服务器。这些客户端连接到一个远程对象,该对象可能会在系统中分配一些资源(在我的例子中是虚拟设备)。
一旦客户端断开连接(假设是因为崩溃),我需要释放那些资源。检测特定客户端已与特定对象断开连接的正确方法是什么?
我尝试过不同的东西:
- 重写
Daemon.clientDisconnected
方法。我从这个方法中得到一个 connection
参数。但我无法将其与对象相关联,因为我无权访问该连接所指的远程对象。
- 在
Daemon.clientDisconnected
中使用 Pyro4.current_context
。这不起作用,因为那是一个线程本地对象。这样一来,如果我连接的客户端多于池中的线程,我会得到重复的上下文。
- 在 Pyro4 项目可用的 "usersession" 示例中使用
Proxy._pyroAnnotations
对我没有帮助,因为我再次从 Pyro4.core.current_context.annotations
属性获得注释,它显示调用 Daemon.clientDisconnected
时我的注释错误(我想是由于与线程相关的问题)。
- 在远程 class 中使用
instance_mode="session"
和 __del__
方法(因为每个客户端都有一个单独的 class 实例,所以该实例应该一旦客户端断开连接就会被销毁)。但这依赖于 __del__
方法,一些 Python 程序员会指出该方法存在一些问题。
我添加了我当前的解决方案作为答案,但我真的很想知道是否有更优雅的方式使用 Pyro4 来执行此操作,因为这种情况是网络编程中的常见模式。
我在客户端使用 Proxy._pyroHandshake
属性作为客户端 ID,并覆盖 Daemon.validateHandshake
和 Daemon.clientDisconnected
。这样,在每个新连接上,我将握手数据(每个客户端唯一)映射到一个连接。但我真的很想知道在 Pyro4 中是否有一种优雅的方式来做到这一点,这是网络编程中经常发生的模式。
请注意,除了使用代理作为客户端的属性,客户端还可以扩展 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()
Pyro 4.63 可能会为此提供一些内置支持,使其更容易实现。你可以在这里 http://pyro4.readthedocs.io/en/latest/tipstricks.html#automatically-freeing-resources-when-client-connection-gets-closed 阅读它,如果你从 Github 克隆当前的母版,你可以尝试一下。或许您可以看看这是否会使您的用例更简单?
我有一个 Pyro4 分布式系统,多个客户端连接到一个服务器。这些客户端连接到一个远程对象,该对象可能会在系统中分配一些资源(在我的例子中是虚拟设备)。
一旦客户端断开连接(假设是因为崩溃),我需要释放那些资源。检测特定客户端已与特定对象断开连接的正确方法是什么?
我尝试过不同的东西:
- 重写
Daemon.clientDisconnected
方法。我从这个方法中得到一个connection
参数。但我无法将其与对象相关联,因为我无权访问该连接所指的远程对象。 - 在
Daemon.clientDisconnected
中使用Pyro4.current_context
。这不起作用,因为那是一个线程本地对象。这样一来,如果我连接的客户端多于池中的线程,我会得到重复的上下文。 - 在 Pyro4 项目可用的 "usersession" 示例中使用
Proxy._pyroAnnotations
对我没有帮助,因为我再次从Pyro4.core.current_context.annotations
属性获得注释,它显示调用Daemon.clientDisconnected
时我的注释错误(我想是由于与线程相关的问题)。 - 在远程 class 中使用
instance_mode="session"
和__del__
方法(因为每个客户端都有一个单独的 class 实例,所以该实例应该一旦客户端断开连接就会被销毁)。但这依赖于__del__
方法,一些 Python 程序员会指出该方法存在一些问题。
我添加了我当前的解决方案作为答案,但我真的很想知道是否有更优雅的方式使用 Pyro4 来执行此操作,因为这种情况是网络编程中的常见模式。
我在客户端使用 Proxy._pyroHandshake
属性作为客户端 ID,并覆盖 Daemon.validateHandshake
和 Daemon.clientDisconnected
。这样,在每个新连接上,我将握手数据(每个客户端唯一)映射到一个连接。但我真的很想知道在 Pyro4 中是否有一种优雅的方式来做到这一点,这是网络编程中经常发生的模式。
请注意,除了使用代理作为客户端的属性,客户端还可以扩展 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()
Pyro 4.63 可能会为此提供一些内置支持,使其更容易实现。你可以在这里 http://pyro4.readthedocs.io/en/latest/tipstricks.html#automatically-freeing-resources-when-client-connection-gets-closed 阅读它,如果你从 Github 克隆当前的母版,你可以尝试一下。或许您可以看看这是否会使您的用例更简单?