使用LineReciever和Twisted Process协议

时间:2015-08-27 02:47:47

标签: twisted

我试图使用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一起使用,还是应该在我的协议中实现线路解析器呢?

1 个答案:

答案 0 :(得分:2)

LineReceiver已经是Protocol,它实现了与IProcessProtocol不同的接口。

幸运的是,Twisted的最新版本已经包含了一个可以满足您需求的适配器 - 即将子进程视为字节流。而不是直接致电spawnProcess,而是使用ProcessEndpoint,您可以传递常规ProtocolFactory,不涉及ProcessProtocol

但是,正如评论者已经指出there's a bug heredisconnecting属性不是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(...))

抱歉延迟回答;虽然你可能已经找到了自己的解决方法,但我希望这对其他有相同问题的人有用!