File: index.rst.bak

package info (click to toggle)
circuits 3.1.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 9,764 kB
  • sloc: python: 15,945; makefile: 131
file content (222 lines) | stat: -rw-r--r-- 6,676 bytes parent folder | download | duplicates (3)
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
.. _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 <https://bitbucket.org/circuits/circuits/src/tip/examples/telnet.py>`_
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:: ../../man/examples/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 adue here's the code:

.. code-block:: python
    :linenos:
    
    #!/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()


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 receieve 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
    <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] ( )>


Testing
-------

To try this example out, download a copy of the
`echoserver Example <https://bitbucket.org/circuits/circuits/src/tip/echoserver.py>`_
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 <https://bitbucket.org/circuits/circuits/src/tip/examples>`_.

.. seealso::
    - :doc:`../../faq`
    - :doc:`../../api/index`