简单的扭曲服务器(twistd .tap)与pexpect实例错误

0 投票
1 回答
1783 浏览
提问于 2025-04-15 19:24

我正在用Twisted创建一个异步服务器套接字,用来发送和接收XML数据。

这个应用运行得很好!但因为我主要想把它嵌入到一个init.d脚本中,让它在后台运行,所以我决定把它变成一个“Twisted应用”,这样就可以用twistd来运行它。

# from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.protocols.basic import LineOnlyReceiver
from twisted.application import internet, service

from xml.etree import ElementTree as ET

from aMuleClass import amulecmd

class DialogueProtocol(LineOnlyReceiver):
    def connectionMade(self):
        print "Connected: %s" % self.transport.getPeer().host
def lineReceived(self, line):
    parsed= ET.XML(line)
    if parsed.attrib['type'] == 'request':
        if parsed.attrib['prompt'] == 'results':
            self.transport.write(self.factory.mule.results())
        elif parsed.attrib['prompt'] == 'downloads':
            self.transport.write(self.factory.mule.downloads())
        else:
            print "Invalid request: %s\n" % line
    else:
        query= parsed.attrib['value']
        if parsed.attrib['type'] == 'search':
            print "must search for %s" % query
            self.factory.mule.search(query)
        elif parsed.attrib['type'] == 'cancel':
            print "must cancel %s" % query
            self.factory.mule.command("cancel %s" % query)
        elif parsed.attrib['type'] == 'download':
            print "must download %s" % query
            self.factory.mule.command("download %s" % query)

class DialogueProtocolFactory(ServerFactory):
def __init__(self):
    self.protocol= DialogueProtocol
    self.mule= amulecmd()

def main():
factory= DialogueProtocolFactory()
port = 14000
#
daemon= internet.TCPServer(port, factory)
application= service.Application("aMuleSocket")
#
daemon.setServiceParent(application)

if __name__ == '__main__':
main()

用“twistd -noy file”命令(调试模式)运行时,一切都非常完美。问题是当我想把脚本放到后台运行时(用“twistd -y file”),套接字就不响应了,日志里充满了来自pexpect的错误信息,而pexpect是在我的amulecmd类中引入的……

pexpect是用来和终端提示应用进行通信的,它会把答案返回给套接字。

日志文件:

2010/02/17 19:54 +0200 [-] Log opened.
2010/02/17 19:54 +0200 [-] twistd 2.5.0 (/usr/bin/python 2.5.2) starting up
2010/02/17 19:54 +0200 [-] reactor class: <class          'twisted.internet.selectreactor.SelectReactor'>
2010/02/17 19:54 +0200 [-] Loading aMuleSocket.tac...
2010/02/17 19:54 +0200 [-] Starting parent
2010/02/17 19:54 +0200 [-] Loaded.
2010/02/17 19:54 +0200 [-] __builtin__.DialogueProtocolFactory starting on 2000
2010/02/17 19:54 +0200 [-] Starting factory <__builtin__.DialogueProtocolFactory instance at 0x82dbd8c>
2010/02/17 19:54 +0200 [__builtin__.DialogueProtocolFactory] Connected: 192.168.0.2
2010/02/17 19:54 +0200 [DialogueProtocol,0,192.168.0.2] Unhandled Error
Traceback (most recent call last):
File "/usr/lib/python2.5/site-packages/twisted/python/log.py", line 48, in      callWithLogger
 return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/lib/python2.5/site-packages/twisted/python/log.py", line 33, in callWithContext
 return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/lib/python2.5/site-packages/twisted/python/context.py", line 59, in callWithContext
 return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/lib/python2.5/site-packages/twisted/python/context.py", line 37, in callWithContext
 return func(*args,**kw)
--- <exception caught here> ---
File "/usr/lib/python2.5/site-packages/twisted/internet/selectreactor.py", line 139, in _doReadOrWrite
 why = getattr(selectable, method)()
File "/usr/lib/python2.5/site-packages/twisted/internet/tcp.py", line 362, in doRead
 return self.protocol.dataReceived(data)
File "/usr/lib/python2.5/site-packages/twisted/protocols/basic.py", line 149, in dataReceived
 self.lineReceived(line)
File "aMuleSocket.tac", line 19, in lineReceived
 self.transport.write(self.factory.mule.downloads())
File "/home/hecyra/amule_scripts/amule-remote-read-only/server/aMuleClass.py", line 60, in downloads
 list= self.command('show DL').splitlines()
File "/home/hecyra/amule_scripts/amule-remote-read-only/server/aMuleClass.py", line 42, in command
 self.prompt()
File "/home/hecyra/amule_scripts/amule-remote-read-only/server/aMuleClass.py", line 27, in prompt
 self.process.expect('aMulecmd')
File "/usr/lib/python2.5/site-packages/pexpect.py", line 1064, in expect
 return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
File "/usr/lib/python2.5/site-packages/pexpect.py", line 1116, in expect_list
 c = self.read_nonblocking (self.maxread, timeout)
File "/usr/lib/python2.5/site-packages/pexpect.py", line 656, in read_nonblocking
 if not self.isalive():
File "/usr/lib/python2.5/site-packages/pexpect.py", line 914, in isalive
raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but   there was no child process. Did someone else call waitpid() on our process?')
pexpect.ExceptionPexpect: isalive() encountered condition where "terminated" is 0,            but there was no child process. Did someone else call waitpid() on our process?

这可能是什么问题呢??我只想把这个脚本放到后台运行 :( 看起来很简单啊。

1 个回答

3

你在把程序变成守护进程之前就创建了一个子进程。变成守护进程后,这个子进程就成了系统的一个子进程,而不是你自己程序的子进程。

你需要从 from twisted.application.service import Service 这个类派生出一个新的类,并在 startService 方法中创建子进程,这个方法会在你变成守护进程后被调用。

就像这个链接里说的: Twisted网络客户端与多进程工作者?

编辑:实现方法

我不能完全测试这个,因为我没有你的 amulecmd,但可以试试更像下面这样的代码:

#!/usr/bin/env python
# vim:ai:et:ts=2:sw=2:bg=dark
from twisted.internet import protocol
from twisted.protocols.basic import LineOnlyReceiver
from twisted.application import service


from xml.etree import ElementTree as ET

from aMuleClass import amulecmd

class DialogueProtocol(LineOnlyReceiver):
  def connectionMade(self):
    print "Connected: %s" % self.transport.getPeer().host
  def lineReceived(self, line):
    parsed= ET.XML(line)
    if parsed.attrib['type'] == 'request':
      if parsed.attrib['prompt'] == 'results':
        self.transport.write(self.factory.mule.results())
      elif parsed.attrib['prompt'] == 'downloads':
        self.transport.write(self.factory.mule.downloads())
      else:
        print "Invalid request: %s\n" % line
    else:
      query= parsed.attrib['value']
      if parsed.attrib['type'] == 'search':
        print "must search for %s" % query
        self.factory.mule.search(query)
      elif parsed.attrib['type'] == 'cancel':
        print "must cancel %s" % query
        self.factory.mule.command("cancel %s" % query)
      elif parsed.attrib['type'] == 'download':
        print "must download %s" % query
        self.factory.mule.command("download %s" % query)

class MyService(service.Service):
  def __init__(self,port=14000):
    self.port = port
  def startService(self):
    self.factory = protocol.Factory()
    self.factory.protocol = DialogueProtocol
    from twisted.internet import reactor
    reactor.callWhenRunning(self.startListening)
  def startListening(self):
    self.factory.mule = amulecmd()
    from twisted.internet import reactor
    self.listener = reactor.listenTCP(self.port,self.factory)
    print "Started listening"
  def stopService(self):
    self.listener.stopListening()

if __name__ == '__main__':
  pass
else:
  application = service.Application("aMuleSocket")
  services = service.IServiceCollection(application)
  MyService().setServiceParent(services)

撰写回答