我正在为现有软件编写一个插件,该插件将使用twisted与Denon AV接收器进行通信。我在我的协议中创建了一个方法powerDenonOff来关闭设备,并在应用程序通过runConcurrentThread启动时让反应器在一个线程中启动。我有另一种方法powerOff,当用户选择在软件中关闭设备时将调用该方法。我无法弄清楚如何从插件类中调用协议中的powerDenonOff方法。
from twisted.internet.protocol import Factory, Protocol
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
class DenonProtocol(LineReceiver):
delimiter='\r'
def lineReceived(self, line):
pass
def connectionMade(self):
pass
def powerDenonOff(self):
self.transport.write("PWSTANDBY")
def __call__(self):
pass
class DenonFactory(Factory):
def __init__(self):
pass
def startedConnecting(self, connector):
pass
def clientConnectionFailed(self, one, two):
pass
def connectionMade(self):
pass
def buildProtocol(self, addr):
return DenonProtocol()
class Plugin(software.PluginClass):
def powerOff(self):
reactor.callInThread(powerDenonOff) #I think this may need to be callFromThread but
#but I left it since that was where the poorly
#worded version of my question left off.
def runConcurrentThread(self):
try:
while True:
#hardcoded for testing
port = 23
host = "111.11.11.11"
denon=DenonFactory()
reactor.connectTCP(host, port, denon)
reactor.run()
except self.StopThread:
pass
def stopConcurrentThread(self):
reactor.callFromThread(reactor.stop)
如何在协议类中找到该方法?有没有更好的方法来实现这一目标?
由于
答案 0 :(得分:1)
您不能多次拨打reactor.run
,因此runConcurrentThread
中的循环无效。每个过程需要启动一次反应器。您可以多次拨打connectTCP
,只要反应堆在某个时刻启动,它们就会起作用。
如果在非主线程中调用runConcurrentThread
,那么您还需要在没有子进程支持的情况下启动reactor(只有在主线程中运行reactor时才支持子进程)。
如果在与stopConcurrentThread
相同的帖子中调用runConcurrentThread
,则无需使用reactor.callFromThread
。但是,如果runConcurrentThread
应该在插件完成之前阻塞,那么就无法在同一个线程中调用stopConcurrentThread
,因此reactor.callFromThread
的使用必须正确。
reactor.run
永远不会提升StopThread
。它会回来。
至于如何从“插件”调用协议实例上的方法,这只是关于在Python中管理引用的问题。回想一下,协议实例给出了对它们工厂的引用(你的工厂没有这样做,但它可以),你的插件类是创建工厂的代码。这意味着您应该能够编写通过工厂引用协议的插件代码。
但是,您也可以使用一种更方便的API - 例如,端点:
endpoint = TCP4ClientEndpoint(reactor, host, port)
factory = ...
d = endpoint.connect(factory)
def connected(protocol):
protocol.powerDenonOff()
protocol.transport.loseConnection()
d.addCallback(connected)
这只是一种可能的方法 - 我不知道哪种连接管理对您的应用程序有意义。如果要维护单个长期连接,则可以保存protocol
引用以供以后使用,而不是调用powerDenonOff
然后断开连接。我怀疑,由于这里的方法是关闭电源,所以连接可能不会持续更长时间,但是......
钩针编织将帮助你完成大部分更无聊和更有趣的部分。我建议尽早看一下。
对于其他人,您只需要非常清楚什么代码在什么线程中运行。允许在reactor.run
以外的其他线程中使用的唯一Twisted API是reactor.callFromThread
。您可以使用它来调用reactor线程中的其他Twisted API。还要记住,每个进程只能运行一个反应器,并且只能运行一次。其余的只是跟踪您需要使用的对象的引用。