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:
pip install circuits
See: Installing
You will need the following components:
All these are available in the circuits library so there is nothing for you to do. Click on each to read more about them.
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:
Without further delay here’s the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #!/usr/bin/env python
import sys
from circuits.io import File
from circuits import handler, Component
from circuits.net.sockets import TCPClient
from circuits.net.events import connect, write
class Telnet(Component):
channel = "telnet"
def init(self, host, port):
self.host = host
self.port = port
TCPClient(channel=self.channel).register(self)
File(sys.stdin, channel="stdin").register(self)
def ready(self, socket):
self.fire(connect(self.host, self.port))
def read(self, data):
print(data.strip())
@handler("read", channel="stdin")
def read_user_input(self, data):
self.fire(write(data))
host = sys.argv[1]
port = int(sys.argv[2])
Telnet(host, port).run()
|
Some important things to note...
Notice that we defined a channel for out Telnet Component?
This is so that the events of TCPClient and File don’t collide. Both of these components share a very similar interface in terms of the events they listen to.
class Telnet(Component):
channel = "telnet"
Notice as well that in defining a channel for our Telnet Component we’ve also “registered” the 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 TCPClient Component.
TCPClient(channel=self.channel).register(self)
In addition to our TCPClient Component being registered with the same channel as our Telnet Component we can also see that we have registered a File Component however we have chosen a different channel here called stdin.
Why? We don’t want the events from TCPClient and subsequently our Telnet Component to collide with the events from File.
So we setup a Component for reading user input by using the File Component and attaching an event handler to our Telnet Component but listening to events from our stdin channel.
File(sys.stdin, channel="stdin").register(self)
@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 Debugger to the Telnet Component.
from circuits import Debugger
(Telnet(host, port) + Debugger()).run()
$ python telnet.py 10.0.0.2 9000
<registered[telnet] (<TCPClient/telnet 21995:MainThread (queued=0) [S]>, <Telnet/telnet 21995:MainThread (queued=4) [R]> )>
<registered[stdin] (<File/stdin 21995:MainThread (queued=0) [S]>, <Telnet/telnet 21995:MainThread (queued=5) [R]> )>
<registered[*] (<Debugger/* 21995:MainThread (queued=0) [S]>, <Telnet/telnet 21995:MainThread (queued=5) [R]> )>
<started[telnet] (<Telnet/telnet 21995:MainThread (queued=4) [R]> )>
<registered[select] (<Select/select 21995:MainThread (queued=0) [S]>, <TCPClient/telnet 21995:MainThread (queued=0) [S]> )>
<ready[telnet] (<TCPClient/telnet 21995:MainThread (queued=0) [S]> )>
<ready[stdin] (<File/stdin 21995:MainThread (queued=0) [S]> )>
<connect[telnet] ('10.0.0.2', 9000 )>
<_open[stdin] ( )>
<connected[telnet] ('10.0.0.2', 9000 )>
<opened[stdin] ('<stdin>', 'r' )>
Hello World!
<_read[stdin] (<open file '<stdin>', mode 'r' at 0x7f32ff5ab0c0> )>
<read[stdin] ('Hello World!\n' )>
<write[telnet] ('Hello World!\n' )>
<_write[telnet] (<socket._socketobject object at 0x11f7f30> )>
<_read[telnet] (<socket._socketobject object at 0x11f7f30> )>
<read[telnet] ('Hello World!\n' )>
Hello World!
^C<signal[telnet] (2, <frame object at 0x12b0a10> )>
<stopped[telnet] (<Telnet/telnet 21995:MainThread (queued=0) [S]> )>
<close[telnet] ( )>
<close[stdin] ( )>
<disconnected[telnet] ( )>
<closed[stdin] ( )>
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.