1

我正在编写一个由服务器(使用 Twisted)和客户端(没有 Twisted)组成的 Python 程序

服务器部分是使用 Twisted 和 Twisted 的应用程序框架实现的,并使用 Twistd 启动以进行守护。

在不同服务器上运行的客户端是一个简单的 Python 脚本,没有任何 Twisted 内容(也没有特定于应用程序框架的内容)。它也应该作为守护进程运行。仅供参考,这是来源:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import sys
import time
import syslog

SERVER_IP = '127.0.0.1' 
SERVER_PORT = 43278 
BEAT_PERIOD = 1

class HeartbeatClient:
    '''
    A Client sending heartbeats to a monitoring server.
    '''
    def __init__(self, server_ip, port, beat_period):
        syslog.syslog( ('Sending heartbeat to IP %s , port %d' +
                        '\n press Ctrl-C to stop\n') 
                        % (SERVER_IP, SERVER_PORT))

    def run(self):
        while True:
            hbSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            hbSocket.sendto('PyHB', (SERVER_IP, SERVER_PORT))
            if __debug__: 
                print 'Time: %s' % time.ctime()
            time.sleep(BEAT_PERIOD)

if __name__ == '__main__':
    hbc = HeartbeatClient() 
    hbc.run()

现在我想知道我是否也可以使用 Twistd 来守护客户端?因此,我会从客户端创建一个 Twisted-Application。但是我看到的所有关于 Twisted 应用程序的示例都实现了一些 Twisted 互联网服务器的东西(比如在我的情况下是 internet.UDPServer ...),我的客户不使用这些东西。

那么是否可以使用 Twistd 将我的客户端作为守护进程启动,我必须进行哪些更改?我应该重写客户端以充分利用 Twisted 吗?如果是,是否有任何类似的示例如何编写基于 Twisted 的网络客户端?

还是我必须为客户端使用不同的守护程序库?有一个很好的库,但我试图保持一致并为客户端和服务器使用相同的守护进程机制。

4

1 回答 1

4

使用 Twisted,作为 tac 文件,您HeartbeatClient将看起来像这样:

from twisted.application.service import Application, Service
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
from twisted.internet.protocol import DatagramProtocol

class HeartbeatClient(Service):
    def startService(self):
        self._call = LoopingCall(self._heartbeat)
        self._call.start(BEAT_PERIOD)

    def stopService(self):
        self._call.stop()

    def _heartbeat(self):
        port = reactor.listenUDP(0, DatagramProtocol())
        port.write('PyHB', (SERVER_IP, SERVER_PORT))
        port.stopListening()

application = Application("PyHB")
HeartbeatClient().setServiceParent(application)

Note the use of reactor.listenUDP, even though you're only sending UDP datagrams, not receiving any. UDP doesn't really have the concept of clients and servers, it only has open ports. All UDP ports can send and receive datagrams. That's why there's only reactor.listenUDP, not reactor.connectUDP.

Aside from that, LoopingCall gives you the loop you want, and putting the code into a custom Service subclass lets you start and stop the loop at the appropriate times.

于 2011-09-09T13:28:13.790 回答