[英]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.