.. _Python Programming Language: http://www.python.org/ Telnet Tutorial =============== Overview -------- Welcome to our 2nd circuits tutorial. This tutorial is going to walk you through the `telnet Example `_ showing you how to various parts of the circuits component library for building a simple TCP client that also accepts user input. Be sure you have circuits installed before you start: .. code-block:: bash pip install circuits See: :doc:`../../start/installing` Components ---------- You will need the following components: 1. The :class:`~.net.sockets.TCPClient` Component 2. The :class:`~.io.file.File` Component 3. The :class:`~.Component` Component All these are available in the circuits library so there is nothing for you to do. Click on each to read more about them. Design ------ .. graphviz:: Telnet.dot The above graph is the overall design of our Telnet application. What's shown here is a relationship of how the components fit together and the overall flow of events. For example: 1. Connect to remote TCP Server. 2. Read input from User. 3. Write input from User to connected Socket. 4. Wait for data from connected Socket and display. .. note:: The :class:`~.core.pollers.Select` Component shown is required by our application for Asynchronous I/O polling however we do not need to explicitly use it as it is automatically imported and registered simply by utilizing the :class:`~.net.sockets.TCPClient` Component. Implementation -------------- Without further delay here's the code: .. literalinclude:: telnet.py :language: python :linenos: :download:`Download telnet.py ` Discussion ---------- Some important things to note... 1. Notice that we defined a ``channel`` for out ``Telnet`` Component? This is so that the events of :class:`~.net.sockets.TCPClient` and :class:`~.io.file.File` don't collide. Both of these components share a very similar interface in terms of the events they listen to. .. code-block:: python class Telnet(Component): channel = "telnet" 2. Notice as well that in defining a ``channel`` for our ``Telnet`` Component we've also "registered" the :class:`~.net.sockets.TCPClient` Component so that it has the same channel as our ``Telnet`` Component. Why? We want our ``Telnet`` Component to receive all of the events of the :class:`~.net.sockets.TCPClient` Component. .. code-block:: python TCPClient(channel=self.channel).register(self) 3. In addition to our :class:`~.net.sockets.TCPClient` Component being registered with the same ``channel`` as our ``Telnet`` Component we can also see that we have registered a :class:`~.io.file.File` Component however we have chosen a different channel here called ``stdin``. Why? We don't want the events from :class:`~.net.sockets.TCPClient` and subsequently our ``Telnet`` Component to collide with the events from :class:`~.io.file.File`. So we setup a Component for reading user input by using the :class:`~.io.file.File` Component and attaching an event handler to our ``Telnet`` Component but listening to events from our ``stdin`` channel. .. code-block:: python File(sys.stdin, channel="stdin").register(self) .. code-block:: python @handler("read", channel="stdin") def read_user_input(self, data): self.fire(write(data)) Here is what the event flow would look like if you were to register the :class:`~.Debugger` to the ``Telnet`` Component. .. code-block:: python from circuits import Debugger (Telnet(host, port) + Debugger()).run() .. code-block:: bash $ python telnet.py 10.0.0.2 9000 , )> , )> , )> )> , )> )> )> <_open[stdin] ( )> ', 'r' )> Hello World! <_read[stdin] (', mode 'r' at 0x7f32ff5ab0c0> )> <_write[telnet] ( )> <_read[telnet] ( )> Hello World! ^C )> )> Testing ------- To try this example out, download a copy of the `echoserver Example `_ and copy and paste the full source code of the ``Telnet`` example above into a file called ``telnet.py``. In one terminal run:: $ python echoserver.py In a second terminal run:: $ python telnet.py localhost 9000 Have fun! For more examples see `examples `_. .. seealso:: - :doc:`../../faq` - :doc:`../../api/index`