2009-12-22 2 views
3

Я пытаюсь реализовать службу с витыми, что довольно близко к «палец» Tutorial здесь: http://twistedmatrix.com/documents/current/core/howto/tutorial/intro.htmlскрученная резьба с подпроцессом.Popen?

У меня есть basic.LineListener ожидания команды, а затем его выполнения, то у меня есть клиентские соединения и выдача команд. Проблема в том, что команде иногда нужно выполнить что-то еще, и для этого я использую модуль подпроцесса python. Дело не только в том, что звонки на общение() висят, это обычная проблема с подпроцессом, и я знаю, как пройти мимо нее. Это то, что подпроцессы.

Вот скрученный код сервера:

from twisted.application import internet, service 
from twisted.internet import protocol, reactor, defer, threads 
from twisted.protocols import basic 
import sys 
import time 
import subprocess 

class MyProtocol(basic.LineReceiver): 
    def lineReceived(self, line): 
     self.go() 
    def go(self): 
     def writeResponse(message): 
      self.transport.write(message + '\r\n') 
      self.transport.loseConnection() 
     threads.deferToThread(self.factory.action).addCallback(writeResponse) 
    def connectionMade(self): 
     self.lines = [] 

class ActionService(service.Service): 
    def __init__(self, **kwargs): 
     pass 
     #self.users = kwargs 

def action(self): 
    print "launching subprocess" 
    sys.stdout.flush() 
    p = subprocess.Popen(["ls"], stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 
    print "launched subprocess, trying to communicate..." 
    sys.stdout.flush() 
    p.communicate() 
    print "returning" 
    sys.stdout.flush() 
    return "%032d" % (0) 

    def getActionFactory(self): 
     f = protocol.ServerFactory() 
     f.protocol = MyProtocol 
     f.action = self.action 
     return f 

reactor.suggestThreadPoolSize(300) 
application = service.Application('Action', uid=0, gid=0) 
f = ActionService() 
serviceCollection = service.IServiceCollection(application) 
internet.TCPServer(31337,f.getActionFactory() 
        ).setServiceParent(serviceCollection) 

... и вот некоторый код клиента:

#!/usr/bin/python 
import time 
import threading 
import socket 

def connectAction(host): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect((host, 31337)) 
    s.send("asdf\r\n") 
    resp = s.recv(32) 
    s.close() 
    return resp 

class sscceThread(threading.Thread): 
    def __init__(self, host): 
     self.host = host 
     threading.Thread.__init__(self) 
    def run(self): 
     connectAction(self.host) 

def main(): 
    threads = [] 
    for i in range(0, 1000): 
     for j in range(0,5): 
      t = sscceThread("localhost") 
      t.start() 
      threads.append(t) 
     for t in threads: 
      t.join() 
     print i 
     time.sleep(1) 
    # print i 

if __name__ == "__main__": 
    main() 

Запустите службу, запустив:

twistd -y sscce_twisted_service.py -l twistdLog; tail -f twistdLog 

И запустить клиент от эксплуатации:

./sscce_twisted_client.py 

Вы должны увидеть, что клиент отправился на пару итераций (я видел, что он прошел целых 10), а затем зависает. Клиентский код содержит 1-секундный сон, так что вы можете сказать разницу между витыми записями журнала от каждой итерации и на ту, который нависает вы увидите что-то подобное в скрученном журнале:

2009-12-22 11:18:47-0800 [MyProtocol,55,127.0.0.1] launching subprocess 
2009-12-22 11:18:47-0800 [MyProtocol,56,127.0.0.1] launching subprocess 
2009-12-22 11:18:47-0800 [MyProtocol,55,127.0.0.1] launched subprocess, trying to communicate... 
2009-12-22 11:18:47-0800 [MyProtocol,57,127.0.0.1] launching subprocess 
2009-12-22 11:18:47-0800 [MyProtocol,58,127.0.0.1] launching subprocess 
2009-12-22 11:18:47-0800 [MyProtocol,56,127.0.0.1] launched subprocess, trying to communicate... 
2009-12-22 11:18:47-0800 [MyProtocol,55,127.0.0.1] returning 
2009-12-22 11:18:47-0800 [MyProtocol,57,127.0.0.1] launching subprocess 
2009-12-22 11:18:47-0800 [MyProtocol,56,127.0.0.1] launching subprocess returning 
2009-12-22 11:18:47-0800 [MyProtocol,59,127.0.0.1] launching subprocess 
2009-12-22 11:18:47-0800 [MyProtocol,58,127.0.0.1] launched subprocess, trying to communicate... 
2009-12-22 11:18:47-0800 [MyProtocol,58,127.0.0.1] returning 
2009-12-22 11:18:47-0800 [MyProtocol,59,127.0.0.1] launched subprocess, trying to communicate... 
2009-12-22 11:18:47-0800 [MyProtocol,59,127.0.0.1] returning 

Особых примечание: MyProtocol, 57. В нем говорится, что он собирается попробовать запустить подпроцесс, но никогда не печатал строку «запущенный подпроцесс, пытающийся связаться». Я думаю, он, должно быть, повесился там.

+1

все кажется прекрасным здесь. PS. используйте 'reactor.spawnProcess' вместо' subprocess' –

+0

Вы хотите принять ответ? –

ответ

6

Как указано в его комментарии, не используйте модуль подпроцесса. На платформах POSIX необходимо (более или менее) обрабатывать сигнал SIGCHLD для обработки дочерних процессов, которые выходят. Поскольку может быть только один обработчик SIGCHLD, несколько библиотек обычно не будут взаимодействовать. Конфликт поддержки дочернего процесса Twisted и поддержка модуля подпроцесса. Либо используйте поддержку Twisted (см. http://twistedmatrix.com/documents/current/core/howto/process.html), либо отключите поддержку Twisted, пройдя installSignalHandlers=False до reactor.run (я рекомендую первый, так как subprocess представляет блокирующие интерфейсы, которые не очень хорошо интегрируются в приложения на основе Twisted).

+0

Twisted также дает вам контроль над унаследованными FD, что иногда весьма удобно. С подпроцессом, если вы хотите использовать stdout/stderr, вы должны наследовать * все * FD, и если один из них является сокером прослушивания, тогда ребенок удерживает его открытым неопределенно, если родительский континент нечетно. Но одно, о чем нужно знать: если вы планируете развернуть это в Windows, вам понадобятся расширения Python для Windows, которые по умолчанию недоступны. Я нашел это трудным путем и должен был переписать для использования subprocess + reactor.iterate, поскольку развертывание дополнительных пакетов в то время не было вариантом. – DNS

+0

Обратите внимание, что эта проблема была исправлена ​​в тубе Twisted, http://twistedmatrix.com/trac/ticket/733, но пока не существует в выпуске. Он будет в Twisted 10.1, когда это будет выпущено. Однако spawnProcess все еще значительно более гибкий и надежный, чем модуль подпроцесса.Например, подпроцесс вызывает «select», даже если Twisted настроен на использование более эффективного цикла событий, а это значит, что вы не сможете создавать подпроцессы на сервере с большим количеством активных подключений, а комментарий JP о блокировке хорошо интегрируется в Twisted. – Glyph

+0

Выпущено Twisted 10.1. http://labs.twistedmatrix.com/2010/07/twisted-1010-released.html – Glyph

Смежные вопросы