Twisted Python: Cannot write to a running spawned

2019-03-01 09:21发布

问题:

My question is, after spawning a process, the child process is looping to get data from its stdin. I would like to write new data to it using either Echo.Process.pipes[0].write(data) or Echo.Process.writeToChild(0,data), but both do not work. Would someone explain what's going on? Or how do I go around this problem?

This is the error I got:

--- <exception caught here> ---
  File "/usr/local/encap/python-2.6.4/lib/python2.6/site-packages/Twisted-9.0.0-py2.6-linux-x86_64.egg/twisted/internet/selectreactor.py", line 146, in _doReadOrWrite
    why = getattr(selectable, method)()
  File "/usr/local/encap/python-2.6.4/lib/python2.6/site-packages/Twisted-9.0.0-py2.6-linux-x86_64.egg/twisted/internet/tcp.py", line 460, in doRead
    return self.protocol.dataReceived(data)
  File "pp1.py", line 30, in dataReceived
    Echo.Process.pipes[0].write(data)
exceptions.KeyError: 0

Thank You,

Q

from sys import executable
from os import environ
import os
from twisted.internet import reactor
from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet import protocol
import sys

implementation = """\
import os
import time
import sys

print "in child", os.getpid()

while (True):
        a = raw_input("")
        if a: print a
"""


class Echo(Protocol):
    Process = None
    def dataReceived(self, data):
        if Echo.Process == None:
                pp = MyPP()
                Echo.Process = reactor.spawnProcess(pp, executable, [executable, "-c", implementation, data], env=environ, childFDs = {0:1, 1:1, 2:2})
        else:
                Echo.Process.pipes[0].write(data)
                #Echo.Process.writeToChild(0,data)
        self.transport.write(data)

class EchoFactory(Factory):
    def buildProtocol(self, addr):
        return Echo()

class MyPP(protocol.ProcessProtocol):
    def connectionMade(self):
        print "connectionMade!"
    def outReceived(self, data):
        print "out"
    def errReceived(self, data):
        print "error", data
    def processExited(self, reason):
        print "processExited"
    def processEnded(self, reason):
        print "processEnded"
        print "quitting"

reactor.listenTCP(8200, EchoFactory())
print 'in parent', os.getpid()
reactor.run()

回答1:

To create a new process on each incoming connection and to redirect all input data to the process' stdin:

#!/usr/bin/python
from twisted.internet import reactor

from twisted.internet import protocol

class Echo(protocol.Protocol):
    def connectionMade(self):
        self.pp = MyPP()
        reactor.spawnProcess(self.pp, 'cat', ['cat'])
    def dataReceived(self, data):
        self.pp.transport.write(data)
    def connectionLost(self, reason):
        self.pp.transport.loseConnection()

class MyPP(protocol.ProcessProtocol):
    def connectionMade(self):
        print "connectionMade!"
    def outReceived(self, data):
        print "out", data,
    def errReceived(self, data):
        print "error", data,
    def processExited(self, reason):
        print "processExited"
    def processEnded(self, reason):
        print "processEnded"
        print "quitting"

factory = protocol.Factory()
factory.protocol = Echo
reactor.listenTCP(8200, factory)
reactor.run()


回答2:

Don't pass childFDs to spawnProcess and don't use the pipes attribute of the resulting process transport object. Neither of these things does what you think. If you drop the use of childFDs and switch back to writeToChild, you'll get the behavior you want.