我试图使用twisted来处理二进制文件生成的数据(无限期地将行转储到stdout上)。由于数据本身是以行分隔的,因此我尝试使用LineReciever而不是尝试解析数据。以下是代码的相关位,似乎造成了麻烦:
class ProtocolBareQDAL41xB(ProcessProtocol, LineReceiver):
...
def outReceived(self, data):
print "Got Data:" + repr(data)
self.dataReceived(data)
def lineReceived(self, line):
print "Got Line: " + line
self._process_line(line)
...
这个'工作'对于输出中的两行中的第一行。我还不知道它是否仅适用于一行,或者它是否适用于除最后一行以外的所有行。结果输出类似于:
$ python BareQDAL41xB.py
Made Connection
<Process pid=16486 status=-1>
Got Data:'No device found!\nMultiple devices found! Please connect only one.\n'
Got Line: No device found!
Got Serial Number : found!
Unhandled Error
Traceback (most recent call last):
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/python/log.py", line 101, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
why = selectable.doRead()
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/internet/process.py", line 274, in doRead
return fdesc.readFromFD(self.fd, self.dataReceived)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/internet/fdesc.py", line 94, in readFromFD
callback(output)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/internet/process.py", line 277, in dataReceived
self.proc.childDataReceived(self.name, data)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/internet/process.py", line 931, in childDataReceived
self.proto.childDataReceived(name, data)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/internet/protocol.py", line 604, in childDataReceived
self.outReceived(data)
File "BareQDAL41xB.py", line 104, in outReceived
self.dataReceived(data)
File "/media/ldata/code/virtualenvs/tendril/local/lib/python2.7/site-packages/twisted/protocols/basic.py", line 573, in dataReceived
self.transport.disconnecting):
exceptions.AttributeError: 'Process' object has no attribute 'disconnecting'
processExited, status 0
processEnded, status 0
LineReciever似乎期望传输实现disconnecting
。
是否可以将扭曲的LineReciever与扭曲的ProcessProtocol一起使用,还是应该在我的协议中实现线路解析器呢?
答案 0 :(得分:2)
LineReceiver
已经是Protocol
,它实现了与IProcessProtocol
不同的接口。
幸运的是,Twisted的最新版本已经包含了一个可以满足您需求的适配器 - 即将子进程视为字节流。而不是直接致电spawnProcess
,而是使用ProcessEndpoint
,您可以传递常规ProtocolFactory
,不涉及ProcessProtocol
。
但是,正如评论者已经指出there's a bug here,disconnecting
属性不是ITransport
的正式属性,而是LineReceiver
(和LineOnlyReceiver
无论如何依赖于它,并且因为它不是接口的一部分,ProcessEndpoint
没有实现它。这肯定是固定的,但与此同时,我们需要解决它。
作为一个幸福的事故,Twisted对包装协议的内置支持WrappingFactory
已经支持disconnecting
属性,特别是因为接口规范理论与最受欢迎的ITransport
实现的现实。因此,即使是无所事事的包装器也能解决这个问题。您可以这样实现:
from zope.interface import implementer
from twisted.internet.interfaces import IStreamClientEndpoint
from twisted.protocols.policies import WrappingFactory
@implementer(IStreamClientEndpoint)
class DisconnectingWorkaroundEndpoint(object):
def __init__(self, endpoint):
self._endpoint = endpoint
def connect(self, protocolFactory):
return self._endpoint.connect(WrappingFactory(protocolFactory))
然后在构建ProcessEndpoint
时,请执行:
endpoint = DisconnectingWorkaroundEndpoint(ProcessEndpoint(...))
抱歉延迟回答;虽然你可能已经找到了自己的解决方法,但我希望这对其他有相同问题的人有用!