[Twisted-Python] How to stop reactor when execution finishes on more than one ssh server?

Jean-Paul Calderone exarkun at divmod.com
Sat Sep 29 14:54:29 EDT 2007


On Sun, 30 Sep 2007 01:08:52 +0800, James Deng <jtdeng at gmail.com> wrote:
>Hi,
>in the sample sshsimpleclient.py, it demostrated how to connect to a ssh
>server and issue a command. my question is what should I do if I want to
>connect to more than one ssh server.
>
>I did try to create more than one SimpleTransport by using the following
>code
>
>HOSTS=[host1, host2, host3]
>protocol.ClientCreator(reactor, SimpleTransport).connectTCP(host1, 22)
>protocol.ClientCreator(reactor, SimpleTransport).connectTCP(host2, 22)
>protocol.ClientCreator(reactor, SimpleTransport).connectTCP(host3, 22)
>reactor.run()
>
>this really behaves as what i expected, and executed the command on all
>remote hosts, but after it finishes, i just hangs there, I know I need a
>place to call something like reactor.stop() when all transport finishes the
>execution. but i do not know where to call it,  need some deffereds? and
>how?

First, you need to know when a single connection is finished.  If what you
are interested in is a channel being closed, then the appropriate callback
is SSHChannel.closed, as sshsimpleclient.py demonstrates.

Then you need for that information to be relayed to the code which is
responsible for knowing that at some point the reactor should be stopped.
sshsimpleclient.py is not a good example of this, since with its approach
to this, when a CatChannel is disconnected, the reactor will always be
stopped.  This makes CatChannel inappropriate for use in any real program.
Instead, you may want to callback a Deferred in your closed implementation.
The Deferred might be one which was supplied to your channel's constructor
and was ultimately created by the same code which knows that the reactor
needs to be stopped.

Finally, you need to aggregate multiple Deferreds into one.  You can do this
using twisted.internet.defer.gatherResults, which takes a list of Deferreds
and returns a Deferred which will be called back when all of the inputs have
been called back.  You can pass the Deferred for each of your channels to
gatherResults and add a callback to the returned Deferred which stops the
reactor.

So, for example (not runnable):

    hosts = [host1, host2, host3]
    closedDeferreds = []
    for host in hosts:
        d = Deferred()
        closedDeferreds.append(d)
        ClientCreator(reactor, SimpleTransport, d).connectTCP(host, 22)
    gatherResults(closedDeferreds).addCallback(lambda ignored: reactor.stop())
    reactor.run()

Jean-Paul




More information about the Twisted-Python mailing list