2011-09-16 17 views
2

基於this example,我正在實施基於Twisted的心跳客戶端/服務器組合。這是我第一個Twisted項目。使用另一個套接字/ TCP/RPC服務擴展現有的Twisted服務以獲取服務信息

基本上它由UDP偵聽器(Receiver)組成,他在接收包上調用偵聽器方法(DetectorService.update)。 DetectorService始終保存着當前活動/非活動客戶端的列表(我擴展了很多示例,但內核仍然相同),使得對於在指定超時時間內看起來斷開連接的客戶端作出反應成爲可能。

這是從現場拍攝的來源:

UDP_PORT = 43278; CHECK_PERIOD = 20; CHECK_TIMEOUT = 15 

import time 
from twisted.application import internet, service 
from twisted.internet import protocol 
from twisted.python import log 

class Receiver(protocol.DatagramProtocol): 
    """Receive UDP packets and log them in the clients dictionary""" 

    def datagramReceived(self, data, (ip, port)): 
     if data == 'PyHB': 
      self.callback(ip) 

class DetectorService(internet.TimerService): 
    """Detect clients not sending heartbeats for too long""" 

    def __init__(self): 
     internet.TimerService.__init__(self, CHECK_PERIOD, self.detect) 
     self.beats = {} 

    def update(self, ip): 
     self.beats[ip] = time.time() 

    def detect(self): 
     """Log a list of clients with heartbeat older than CHECK_TIMEOUT""" 
     limit = time.time() - CHECK_TIMEOUT 
     silent = [ip for (ip, ipTime) in self.beats.items() if ipTime < limit] 
     log.msg('Silent clients: %s' % silent) 

application = service.Application('Heartbeat') 
# define and link the silent clients' detector service 
detectorSvc = DetectorService() 
detectorSvc.setServiceParent(application) 
# create an instance of the Receiver protocol, and give it the callback 
receiver = Receiver() 
receiver.callback = detectorSvc.update 
# define and link the UDP server service, passing the receiver in 
udpServer = internet.UDPServer(UDP_PORT, receiver) 
udpServer.setServiceParent(application) 
# each service is started automatically by Twisted at launch time 
log.msg('Asynchronous heartbeat server listening on port %d\n' 
    'press Ctrl-C to stop\n' % UDP_PORT) 

這心跳服務器運行在後臺守護進程。現在

我的問題

我需要能夠運行一個腳本「外部」打印控制檯,它的接收他的一生(self.beats)時要收集離線/在線客戶端的數量。是這樣的:

$ pyhb showactiveclients 
3 clients online 
$ pyhb showofflineclients 
1 client offline 

所以我需要添加某種額外的服務器(端口,TCP,RPC - 沒關係的主要觀點是,我能夠建立一個客戶端腳本與以上行爲)到我的DetectorService,它允許從外部連接到它。它應該只是迴應一個請求。

該服務器需要訪問正在運行的檢測器服務實例的內部變量,所以我的猜測是我必須用某種附加服務來擴展DetectorService。

經過幾個小時試圖將檢測器服務與其他幾項服務相結合,我仍然不知道什麼是實現該行爲的最佳方法。所以我希望有人能夠給我至少提供如何開始解決這個問題的基本提示。 在此先感謝!

回答

3

我想你已經有了解決方案的總體思路,因爲你已經將它應用於ReceiverDetectorService之間的交互。這個想法是讓你的對象引用其他對象,讓它們做他們需要做的事情。

因此,考慮到響應基礎上beats數據與結果的請求Web服務:

from twisted.web.resource import Resource 

class BeatsResource(Resource): 
    # It has no children, let it respond to the/URL for brevity. 
    isLeaf = True 

    def __init__(self, detector): 
     Resource.__init__(self) 
     # This is the idea - BeatsResource has a reference to the detector, 
     # which has the data needed to compute responses. 
     self._detector = detector 

    def render_GET(self, request): 
     limit = time.time() - CHECK_TIMEOUT 
     # Here, use that data. 
     beats = self._detector.beats 
     silent = [ip for (ip, ipTime) in beats.items() if ipTime < limit] 
     request.setHeader('content-type', 'text/plain') 
     return "%d silent clients" % (len(silent),) 

# Integrate this into the existing application 
application = service.Application('Heartbeat') 
detectorSvc = DetectorService() 
detectorSvc.setServiceParent(application) 
. 
. 
. 
from twisted.web.server import Site 
from twisted.application.internet import TCPServer 

# The other half of the idea - make sure to give the resource that reference 
# it needs. 
root = BeatsResource(detectorSvc) 
TCPServer(8080, Site(root)).setServiceParent(application) 
+0

謝謝,我能解決我的問題。但是'TCPServer(8080,Site(root))。setServiceParent(application)'不起作用(Twisted中沒有這樣的類,並且Python中的TCPServer沒有'setServiceParent',我使用'reactor.listenTCP(8080 ,Site(root))''現在在我的代碼中, – ifischer

+0

@ifischer:有'taiTCPServer'類(它是動態生成的)。http://twistedmatrix.com/documents/current/api/twisted.application .internet.html – jfs