простой витой сервер (twistd .tap) с ошибкой экземпляра pexpect - PullRequest
0 голосов
/ 17 февраля 2010

Я создал сокет асинхронного сервера, который отправляет и получает XML с использованием витой.

Приложение прекрасно работает! но поскольку моей главной целью было встроить его в сценарий init.d и запустить его в фоновом режиме, я решил преобразовать его в «витое приложение», чтобы запустить его с помощью 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, который импортирован в мой класс 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 голосов
/ 17 февраля 2010

Вы порождаете дочерний процесс перед демонизацией. После демонизации этот потомок теперь является потомком init, а не потомком вашего демона.

Вам необходимо создать подкласс from twisted.application.service import Service и запустить дочерний процесс в startService, который будет вызываться после демонизации.

Á La: Скрученный сетевой клиент с многопроцессорными рабочими?

Редактировать: реализация

Я не могу проверить это полностью, так как у меня нет вашего 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)
...