[英]How to limit the number of simultaneous connections in Twisted
所以我建立了一个扭曲的服务器,我想知道限制同时连接数的最佳方法是什么?
让我的工厂回归没有最好的方法吗? 当我这样做时,我抛出了很多例外,例如:
exceptions.AttributeError: 'NoneType' object has no attribute 'makeConnection'
我想在某种程度上让客户只是坐在队列中,直到当前连接数回落,但我不知道如何异步执行。
目前我正在使用我的工厂这样做:
class HandleClientFactory(Factory):
def __init__(self):
self.numConnections = 0
def buildProtocol(self, addr):
#limit connection number here
if self.numConnections >= Max_Clients:
logging.warning("Reached maximum Client connections")
return None
return HandleClient(self)
哪个有效,但断开连接而不是等待,并且还会抛出许多未处理的错误。
你必须自己构建它。 幸运的是,这些碎片大部分都是这样做的(你可能会要求稍微更合适的碎片但是......)
首先,为了避免AttributeError
(确实导致连接被关闭),请确保从buildProtocol
方法返回IProtocol
提供程序。
class DoesNothing(Protocol):
pass
class YourFactory(Factory):
def buildProtocol(self, addr):
if self.currentConnections < self.maxConnections:
return Factory.buildProtocol(self, addr)
protocol = DoesNothing()
protocol.factory = self
return protocol
如果您使用此工厂(填写缺失的部分 - 例如,初始化maxConnections
以及正确跟踪currentConnections
),那么您将发现一旦达到限制就连接的客户端将获得DoesNothing
协议。 他们可以根据自己的喜好向此协议发送尽可能多的数据。 它将丢弃所有。 它永远不会向他们发送任何数据。 它将使连接保持打开状态,直到它们关闭它。 简而言之,它什么都不做。
但是,一旦连接数低于限制,您还希望客户实际接收服务。
要做到这一点,你需要更多的东西:
对于第一个,您可以使用大多数传输的功能来“暂停”:
class PauseTransport(Protocol):
def makeConnection(self, transport):
transport.pauseProducing()
class YourFactory(Factory):
def buildProtocol(self, addr):
if self.currentConnections < self.maxConnections:
return Factory.buildProtocol(self, addr)
protocol = PauseTransport()
protocol.factory = self
return protocol
PauseTransport
类似于DoesNothing
但具有次要(和有用)的区别,只要它连接到传输,它就会告诉传输暂停。 因此,不会从连接中读取任何数据,并且只要您准备好处理它,它们都将保持缓冲状态。
对于下一个要求,存在许多可能的解决方案。 最简单的方法之一是使用工厂作为存储:
class PauseAndStoreTransport(Protocol):
def makeConnection(self, transport):
transport.pauseProducing()
self.factory.addPausedTransport(transport)
class YourFactory(Factory):
def buildProtocol(self, addr):
# As above
...
def addPausedTransport(self, transport):
self.transports.append(transport)
再次,通过正确的设置(例如,初始化transports
属性),您现在拥有一个列表,其中包含与您在等待服务之上的并发限制之上接受的连接相对应的所有传输。
对于最后一个要求,所有必要的是实例化和初始化实际上能够为您的客户提供服务的协议。 实例化很容易(这是你的协议,你可能知道它是如何工作的)。 初始化主要是调用makeConnection
方法:
class YourFactory(Factory):
def buildProtocol(self, addr):
# As above
...
def addPausedTransport(self, transport):
# As above
...
def oneConnectionDisconnected(self)
self.currentConnections -= 1
if self.currentConnections < self.maxConnections:
transport = self.transports.pop(0)
protocol = self.buildProtocol(address)
protocol.makeConnection(transport)
transport.resumeProducing()
我已经省略了跟踪buildProtocol
所需的address
参数的细节(从它的起始点transport
到程序的这一部分,如果你的程序应该清楚如何为原始地址值做类似的事情实际上想要它)。
除此之外,这里发生的一切都是你采取下一个排队的传输(你可以使用不同的调度算法,例如LIFO)并将其连接到你选择的协议,就像Twisted一样。 最后,撤消先前的暂停操作,以便数据开始流动。
或者......差不多。 除非Twisted传输实际上没有任何方式来改变它们传递数据的协议,否则这将非常灵活。 因此,如上所述,来自客户端的数据实际上将被传递到原始PauseAndStoreTransport
协议实例。 你可以解决这个问题(“hack”显然是正确的词)。 将transport 和 PauseAndStoreTransport
实例存储在工厂的列表中,然后:
def oneConnectionDisconnected(self)
self.currentConnections -= 1
if self.currentConnections < self.maxConnections:
originalProtocol, transport = self.transports.pop(0)
newProtocol = self.buildProtocol(address)
originalProtocol.dataReceived = newProtocol.dataReceived
originalProtocol.connectionLost = newProtocol.connectionLost
newProtocol.makeConnection(transport)
transport.resumeProducing()
现在,传输要调用方法的对象已将其方法替换为您希望调用方法的对象的方法。 再次,这显然是一个黑客。 如果你愿意的话,你可以把不太讨厌的东西放在一起(例如,明确支持委托给另一个协议的第三个协议类)。 这个想法是一样的 - 它只会在你的键盘上磨损。 对于它的价值,我怀疑使用Tubes做类似的事情可能更容易,更少打字,但我现在将尝试基于该库的解决方案。
我已经避免解决保持currentConnections
正确更新的问题。 由于您的问题中已经有numConnections
,我假设您知道如何管理该部分。 我在这里的最后一步所做的就是假设你做减量步骤的方法是在工厂调用oneConnectionDisconnected
。
我还避免解决排队连接变得无聊并消失的事件。 这将主要工作是写-扭曲不会注意到的连接被关闭,直到调用resumeProducing
然后connectionLost
将您的应用程序协议来调用。 这应该没问题,因为您的协议无论如何都需要处理丢失的连接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.