[Twisted-Python] twisted.conch.telnet example?

Jean-Paul Calderone exarkun at divmod.com
Tue Jun 26 15:08:01 EDT 2007


On Tue, 26 Jun 2007 10:03:26 -0700, Stephen Hansen <apt.shansen at gmail.com> wrote:
>Hello all. :)

Hey!

>
>I'm trying to learn Twisted, and to replace irritating telnetlib code for a
>simple telnet client application to do so. The problem is I'm slightly lost
>as to where to start with the twisted.conch.telnet library, so was wondering
>if anyone could point me to a simple example.

Cool.  :)

>
>So far, I understand the whole client factory thing-- but where I start
>getting lost is where we get to the "protocol" point (I know I know-- so
>early to get confused!).
>
>Specifically, in the buildProtocol method of a ReconnectingClientFactory
>instance.. what should I be returning a subclass of?

The documentation for this part of Twisted is basically completely
missing.  That'd be my fault, I really should have written some, either
when telnet was implemented or some time in the two years since. ;)

So, to start, I'll try to give a high-level overview.


Then there's t.c.telnet.

>
>There's a telnet.Telnet, which /looks/ like it would be handling all of the
>telnet negotiation nicely, but it has methods like "def enableRemote" that
>call "self.protocol.enableRemote".. and I'm not sure what should be put
>there, or how that should have been handled.

Yep.  t.c.telnet.Telnet is a Protocol subclass and so implements
IProtocol: it is the class which actually implements the telnet
protocol.  It goes right on top of an ITCPTransport and its dataReceived
knows about telnet escapes and the other features of the telnet
protocol.  When it gets bytes which represent some telnet protocol
action, a Telnet instance calls either negotiate or commandReceived on
itself.  The default implementation of these methods dispatches the
event to handlers defined by negotiationMap and
enableLocal/disableLocal/enableRemote/disableRemote, respectively.  In
turn, {enable,disable}{Local,Remote} dispatch to another object,
self.protocol, as you noticed.

There's also a subclass of Telnet, TelnetTransport.  TelnetTransport
takes a protocol class and some arguments to its initializer.  When
TelnetTransport is connected to an ITCPTransport, it instantiates the
class it was given and saves the instance as self.protocol.  As a Telnet
subclass, this means that the protocol class passed to TelnetTransport's
initializer can now control how negotiations happen and how to respond
to commands.

>
>My best success so far was to have it return a subclass of
>telnet.StatefulTelnetProtocol. It does the "basis" of what I want: a
>line-oriented output from the telnet protocol connection. However, it also
>returns all the negotiation characters, so it seems like it's not actually
>implementing the telnet negotiation part itself.
>

StatefulTelnetProtocol is a TelnetProtocol.  TelnetProtocol is the
intended base class for anything which is passed to TelnetTransport.
TelnetProtocol is an ITelnetProtocol, so actually anywhere a
TelnetProtocol class will work, so will any other class which implements
ITelnetProtocol.

TelnetProtocol doesn't know anything about the actual telnet protocol -
its name attempts to convey that it /is/ a protocol /for/ telnet: it can
receive application level bytes (dataReceived, inherited from
IProtocol/Protocol), but it can also handle events which can only happen
when you're using telnet: those four enable/disable methods, plus some
catch-alls for negotiation about options which aren't recognized.  Since
TelnetProtocol doesn't know the telnet protocol, if you hook it directly
up to an ITCPTransport, it'll just think everything it gets is
application data, even telnet negotiation sequences.

>Then there's telnet.TelnetBootstrapProtocol which looks very
>interesting but looks like its mostly handling telnet features I'm not
>interested in (various line modes, screen size negotiation, etc)
>yet... and a telnet.TelnetProtocol that I'm very confused by.. it's
>inheriting from ITelnetProtocol which appears to define the basic
>negotiation methods, but it doesn't appear to -do- anything. (And
>telnet.Telnet, which does notinherit from that interface, does appear
>to support -doing- the negotiation)

TelnetBootstrapProtocol is another one like StatefulTelnetProtocol - it
adds some features which may or may not be interesting, but it won't
work by itself, it needs TelnetTransport to actually parse the protocol.

>
>This might all be a lot of babbling, and if so-- sorry! I'm just not sure
>where to get started on understanding what's going on in this module to make
>use of it. :) I tried googling around to see if I could find a simple
>display of gluing the conch modules together to produce a line-oriented
>telnet client connection that appeared to handle the negotiation ... just to
>get started-- and I can't find one. Does anyone know of one? (Or, if I give
>you $0.25, could you throw one together? :))

Hopefully the above has given you a better idea of what all the pieces
are supposed to be doing.  Here's an example of how you might hook them
up to each other, by way of a client which prints all application data
it receives:

  from twisted.internet import reactor
  from twisted.internet.protocol import ClientFactory
  from twisted.conch.telnet import TelnetTransport, TelnetProtocol

  class TelnetPrinter(TelnetProtocol):
      def dataReceived(self, bytes):
          print 'Received:', repr(bytes)

  class TelnetFactory(ClientFactory):
      def buildProtocol(self, addr):
          return TelnetTransport(TelnetPrinter)

  reactor.connectTCP(host, port, TelnetFactory())

For something line oriented, you might mix in LineReceiver (as
StatefulTelnetProtocol does) or instantiate one directly yourself in a
TelnetProtocol subclass and feed it bytes in your dataReceived
implementation.

Hope this helps,

Jean-Paul




More information about the Twisted-Python mailing list