2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
<html xmlns="http://www.w3.org/1999/xhtml">
7
<title>Writing Servers</title>
11
<h1>Writing Servers</h1>
15
<p>Twisted is a framework designed to be very flexible and let
16
you write powerful servers. The cost of this flexibility is a
17
few layers in the way to writing your server.</p>
19
<p>This document describes the
20
<code class="API" base="twisted.internet.protocol">Protocol</code>
22
implement protocol parsing and handling. If you are implementing
23
an application then you should read this document second, after
24
first reading the top level overview of how to begin writing your
25
Twisted application, in <a href="plugin.xhtml">Writing Plug-Ins
26
for Twisted</a>. This document is only relevant to TCP, SSL and
27
Unix socket servers, there is a <a href="udp.xhtml">separate document</a>
30
<p>Your protocol handling class will usually subclass <code
31
class="API">twisted.internet.protocol.Protocol</code>. Most
32
protocol handlers inherit either from this class or from one of
33
its convenience children. An instance of the protocol class
34
might be instantiated per-connection, on demand, and might go
35
away when the connection is finished. This means that
36
persistent configuration is not saved in the
37
<code>Protocol</code>.</p>
39
<p>The persistent configuration is kept in a Factory class,
40
which usually inherits from <code
41
class="API">twisted.internet.protocol.Factory</code>. The
42
default factory class just instantiates each <code>Protocol</code>, and then
43
sets on it an attribute called <code>factory</code> which
44
points to itself. This lets every <code>Protocol</code> access,
45
and possibly modify, the persistent configuration.</p>
47
<p>It is usually useful to be able to offer the same service on
48
multiple ports or network addresses. This is why the <code>Factory</code>
49
does not listen to connections, and in fact does not
50
know anything about the network. See <code
51
class="API">twisted.internet.interfaces.IReactorTCP.listenTCP</code>,
52
and the other <code>IReactor*.listen*</code> APIs for more
55
<p>This document will explain each step of the way.</p>
59
<p>As mentioned above, this, along with auxiliary classes and
60
functions, is where most of the code is. A Twisted protocol
61
handles data in an asynchronous manner. What this means is that
62
the protocol never waits for an event, but rather responds to
63
events as they arrive from the network.</p>
65
<p>Here is a simple example:</p>
67
from twisted.internet.protocol import Protocol
71
def dataReceived(self, data):
72
self.transport.write(data)
75
<p>This is one of the simplest protocols. It simply writes back
76
whatever is written to it, and does not respond to all events. Here is an
77
example of a Protocol responding to another event:</p>
79
from twisted.internet.protocol import Protocol
83
def connectionMade(self):
84
self.transport.write("An apple a day keeps the doctor away\r\n")
85
self.transport.loseConnection()
88
<p>This protocol responds to the initial connection with a well
89
known quote, and then terminates the connection.</p>
91
<p>The connectionMade event is usually where set up of the
92
connection object happens, as well as any initial greetings (as
93
in the QOTD protocol above, which is actually based on RFC
94
865). The <code>connectionLost</code> event is where tearing down of any
95
connection-specific objects is done. Here is an example:</p>
97
from twisted.internet.protocol import Protocol
101
def connectionMade(self):
102
self.factory.numProtocols = self.factory.numProtocols+1
103
if self.factory.numProtocols > 100:
104
self.transport.write("Too many connections, try later")
105
self.transport.loseConnection()
107
def connectionLost(self, reason):
108
self.factory.numProtocols = self.factory.numProtocols-1
110
def dataReceived(self, data):
111
self.transport.write(data)
114
<p>Here <code>connectionMade</code> and
115
<code>connectionLost</code> cooperate to keep a count of the
116
active protocols in the factory. <code>connectionMade</code>
117
immediately closes the connection if there are too many active
120
<h3>Using the Protocol</h3>
122
<p>In this section, I will explain how to test your protocol
123
easily. (In order to see how you should write a production-grade Twisted
124
server, though, you should read the <a href="plugin.xhtml" >Writing Plug-Ins
125
for Twisted</a> HOWTO as well).</p>
127
<p>Here is code that will run the QOTD server discussed
130
from twisted.internet.protocol import Protocol, Factory
131
from twisted.internet import reactor
133
class QOTD(Protocol):
135
def connectionMade(self):
136
self.transport.write("An apple a day keeps the doctor away\r\n")
137
self.transport.loseConnection()
139
# Next lines are magic:
141
factory.protocol = QOTD
143
# 8007 is the port you want to run under. Choose something >1024
144
reactor.listenTCP(8007, factory)
148
<p>Don't worry about the last 6 magic lines -- you will
149
understand what they do later in the document.</p>
151
<h3>Helper Protocols</h3>
153
<p>Many protocols build upon similar lower-level abstraction.
154
The most popular in internet protocols is being line-based.
155
Lines are usually terminated with a CR-LF combinations.</p>
157
<p>However, quite a few protocols are mixed - they have
158
line-based sections and then raw data sections. Examples
159
include HTTP/1.1 and the Freenet protocol.</p>
161
<p>For those cases, there is the <code>LineReceiver</code>
162
protocol. This protocol dispatches to two different event
163
handlers - <code>lineReceived</code> and
164
<code>rawDataReceived</code>. By default, only
165
<code>lineReceived</code> will be called, once for each line.
166
However, if <code>setRawMode</code> is called, the protocol
167
will call <code>rawDataReceived</code> until
168
<code>setLineMode</code> is called again.</p>
170
<p>Here is an example for a simple use of the line
173
from twisted.protocols.basic import LineReceiver
175
class Answer(LineReceiver):
177
answers = {'How are you?': 'Fine', None : "I don't know what you mean"}
179
def lineReceived(self, line):
180
if self.answers.has_key(line):
181
self.sendLine(self.answers[line])
183
self.sendLine(self.answers[None])
186
<p>Note that the delimiter is not part of the line.</p>
188
<p>Several other, less popular, helpers exist, such as a
189
netstring based protocol and a prefixed-message-length
192
<h3>State Machines</h3>
194
<p>Many Twisted protocol handlers need to write a state machine
195
to record the state they are at. Here are some pieces of advice
196
which help to write state machines:</p>
199
<li>Don't write big state machines. Prefer to write a state
200
machine which deals with one level of abstraction at a
203
<li>Use Python's dynamicity to create open ended state
204
machines. See, for example, the code for the SMTP
207
<li>Don't mix application-specific code with Protocol
208
handling code. When the protocol handler has to make an
209
application-specific call, keep it as a method call.</li>
214
<p>As mentioned before, usually the class <code
215
class="API">twisted.internet.protocol.Factory</code> works,
216
and there is no need to subclass it. However, sometimes there
217
can be factory-specific configuration of the protocols, or
218
other considerations. In those cases, there is a need to
219
subclass <code>Factory</code>.</p>
221
<p>For a factory which simply instantiates instances of a
222
specific protocol class, simply instantiate
223
<code>Factory</code>, and sets its <code>protocol</code> attribute:</p>
225
from twisted.internet.protocol import Factory
226
from twisted.protocols.wire import Echo
228
myFactory = Factory()
229
myFactory.protocol = Echo
232
<p>If there is a need to easily construct factories for a
233
specific configuration, a factory function is often useful:</p>
235
from twisted.internet.protocol import Factory, Protocol
237
class QOTD(Protocol):
239
def connectionMade(self):
240
self.transport.write(self.factory.quote+'\r\n')
241
self.transport.loseConnection()
244
def makeQOTDFactory(quote=None):
246
factory.protocol = QOTD
247
factory.quote = quote or 'An apple a day keeps the doctor away'
251
<p>A Factory has two methods to perform application-specific
252
building up and tearing down (since a Factory is frequently
253
persisted, it is often not appropriate to do them in <code>__init__</code>
254
or <code>__del__</code>, and would frequently be too early or too late).</p>
256
<p>Here is an example of a factory which allows its Protocols
257
to write to a special log-file:</p>
259
from twisted.internet.protocol import Factory
260
from twisted.protocols.basic import LineReceiver
263
class LoggingProtocol(LineReceiver):
265
def lineReceived(self, line):
266
self.factory.fp.write(line+'\n')
269
class LogfileFactory(Factory):
271
protocol = LoggingProtocol
273
def __init__(self, fileName):
276
def startFactory(self):
277
self.fp = open(self.file, 'a')
279
def stopFactory(self):
283
<h3>Putting it All Together</h3>
285
<p>So, you know what factories are, and want to run the QOTD
286
with configurable quote server, do you? No problems, here is an
290
from twisted.internet.protocol import Factory, Protocol
291
from twisted.internet import reactor
293
class QOTD(Protocol):
295
def connectionMade(self):
296
self.transport.write(self.factory.quote+'\r\n')
297
self.transport.loseConnection()
300
class QOTDFactory(Factory):
304
def __init__(self, quote=None):
305
self.quote = quote or 'An apple a day keeps the doctor away'
307
reactor.listenTCP(8007, QOTDFactory("configurable quote"))
311
<p>The only lines you might not understand are the last two.</p>
314
base="twisted.internet.interfaces.IReactorTCP">listenTCP</code> is
315
the method which connects a <code>Factory</code> to the network.
316
It uses the reactor interface, which lets many different loops handle
317
the networking code, without modifying end-user code, like this.
318
As mentioned above, if you want to write your code to be a production-grade
319
Twisted server, and not a mere 20-line hack, you will want to
320
use <a href="application.xhtml">the Application object</a>.</p>