我有一个Twisted项目,它试图在JSON中通过TCP重新广播收集的数据。我本质上有一个USB库,我需要订阅并在while循环中同步读取,如下所示:
while True:
for line in usbDevice.streamData():
data = MyBrandSpankingNewUSBDeviceData(line)
# parse the data, convert to JSON
output = convertDataToJSON(data)
# broadcast the data
...
问题当然是...
。基本上,我需要在服务器启动后立即启动此过程,并在服务器结束时(Protocol.doStart
和Protocol.doStop
)结束它并使其持续运行并向每个连接的广播output
运输。
我怎样才能在Twisted中执行此操作?显然,我需要在自己的线程中运行while循环,但我怎么能订阅"客户听取输出?同样重要的是,USB数据收集只运行一次,因为它可能会严重混乱,使其不止一次运行。
简而言之,这就是我的架构:
我们希望在可用时将数据发送到所有连接的客户端。我怎么能在Twisted中做到这一点?
答案 0 :(得分:2)
您可能想要做的一件事是尝试扩展通用协议/传输独立性。即使您需要一个具有长时间运行循环的线程,您也可以将其隐藏在协议中。好处和往常一样:协议变得更容易测试,如果你设法有一个读取USB事件的非线程实现,你可以在不改变协议的情况下改变传输。
from threading import Thread
class USBThingy(Thread):
def __init__(self, reactor, device, protocol):
self._reactor = reactor
self._device = device
self._protocol = protocol
def run(self):
while True:
for line in self._device.streamData():
self._reactor.callFromThread(self._protocol.usbStreamLineReceived, line)
使用callFromThread
是使该解决方案可用的部分原因。它确保在反应器线程中调用usbStreamLineReceived
方法,而不是在从USB设备读取的线程中调用。因此,从协议对象的角度来看,线程没有什么特别之处:它只是在需要处理一些数据的时候暂时调用它的方法。
您的协议只需要以某种方式实现usbStreamLineReceived
,并实现您的其他特定于应用程序的逻辑,例如保留观察者列表:
class SomeUSBProtocol(object):
def __init__(self):
self.observers = []
def usbStreamLineReceived(self, line):
data = MyBrandSpankingNewUSBDeviceData(line)
# broadcast the data
for obs in self.observers[:]:
obs(output)
然后观察者可以用这个类的实例注册自己,并用数据做任何他们想做的事情:
class USBObserverThing(Protocol):
def connectionMade(self):
self.factory.usbProto.observers.append(self.emit)
def connectionLost(self):
self.factory.usbProto.observers.remove(self.emit)
def emit(self, output):
# parse the data, convert to JSON
output = convertDataToJSON(data)
self.transport.write(output)
把它们连在一起:
usbDevice = ...
usbProto = SomeUSBProtocol()
thingy = USBThingy(reactor, usbDevice, usbProto)
thingy.start()
factory = ServerFactory()
factory.protocol = USBObserverThing
factory.usbProto = usbProto
reactor.listenTCP(12345, factory)
reactor.run()
你可以想象一个更好的观察者注册/取消注册API(比如使用实际方法而不是直接访问该列表)。您还可以设想为USBThingy
提供关闭方法,以便SomeUSBProtocol
可以控制何时停止运行(因此您的流程实际上可以退出)。