使用另一个Socket / TCP / RPC服务扩展现有的Twisted Service以获取Service信息

时间:2011-09-16 14:02:48

标签: twisted twisted.web twisted.internet

我正在基于this example实现基于Twisted的Heartbeat客户端/服务器组合。这是我的第一个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)

此心跳服务器在后台运行为守护程序。

现在我的问题

我需要能够“外部”运行脚本来打印控制台上的离线/在线客户端数量,Receiver在其生命周期内收集这些客户端(self.beats)。像这样:

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

所以我需要添加一些额外的服务器(Socket,Tcp,RPC - 无关紧要。重点是我能够用上述行为构建一个客户端脚本)到我的DetectorService,允许从外部连接到它。它应该只是对请求做出回应。

此服务器需要访问正在运行的detectorervice实例的内部变量,因此我的猜测是我必须使用某种附加服务扩展DetectorService。

在尝试将探测器服务与其他几项服务结合起来几个小时之后,我仍然不知道实现这种行为的最佳方法是什么。所以我希望有人能给我至少一些必要的提示如何开始解决这个问题。 在此先感谢!!!

1 个答案:

答案 0 :(得分:3)

我认为您已经对此处的解决方案有了一般的了解,因为您已将其应用于ReceiverDetectorService之间的互动。我们的想法是让您的对象引用其他对象,让他们做他们需要做的事情。

因此,请考虑一个响应请求的Web服务,其结果基于beats数据:

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)