1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: UDP Networking</title>
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">UDP Networking</h1>
9
<div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">DatagramProtocol</a></li><li><a href="#auto2">Connected UDP</a></li><li><a href="#auto3">Multicast UDP</a></li><li><a href="#auto4">Acknowledgements</a></li></ol></div>
13
<h2>Overview<a name="auto0"/></h2>
15
<p>Unlike TCP, UDP has no notion of connections. A UDP socket can receive
16
datagrams from any server on the network, and send datagrams to any host
17
on the network. In addition, datagrams may arrive in any order, never
18
arrive at all, or be duplicated in transit.</p>
20
<p>Since there are no multiple connections, we only use a single object,
21
a protocol, for each UDP socket. We then use the reactor to connect
22
this protocol to a UDP transport, using the
23
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IReactorUDP.html" title="twisted.internet.interfaces.IReactorUDP">twisted.internet.interfaces.IReactorUDP</a></code>
26
<h2>DatagramProtocol<a name="auto1"/></h2>
28
<p>At the base, the place where you actually implement the protocol
29
parsing and handling, is the DatagramProtocol class. This class will
30
usually be decended from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.protocol.DatagramProtocol.html" title="twisted.internet.protocol.DatagramProtocol">twisted.internet.protocol.DatagramProtocol</a></code>. Most
31
protocol handlers inherit either from this class or from one of its
32
convenience children. The DatagramProtocol class receives datagrams, and
33
can send them out over the network. Received datagrams include the
34
address they were sent from, and when sending datagrams the address to
35
send to must be specified.</p>
37
<p>Here is a simple example:</p>
38
<pre class="python"><p class="py-linenumber"> 1
49
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">DatagramProtocol</span>
50
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
52
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Echo</span>(<span class="py-src-parameter">DatagramProtocol</span>):
54
<span class="py-src-keyword">def</span> <span class="py-src-identifier">datagramReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">data</span>, (<span class="py-src-parameter">host</span>, <span class="py-src-parameter">port</span>)):
55
<span class="py-src-keyword">print</span> <span class="py-src-string">"received %r from %s:%d"</span> % (<span class="py-src-variable">data</span>, <span class="py-src-variable">host</span>, <span class="py-src-variable">port</span>)
56
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">data</span>, (<span class="py-src-variable">host</span>, <span class="py-src-variable">port</span>))
58
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenUDP</span>(<span class="py-src-number">9999</span>, <span class="py-src-variable">Echo</span>())
59
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
62
<p>As you can see, the protocol is registed with the reactor. This means
63
it may be persisted if it's added to an application, and thus it has
64
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.protocol.DatagramProtocol.startProtocol.html" title="twisted.internet.protocol.DatagramProtocol.startProtocol">twisted.internet.protocol.DatagramProtocol.startProtocol</a></code>
65
and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.protocol.DatagramProtocol.stopProtocol.html" title="twisted.internet.protocol.DatagramProtocol.stopProtocol">twisted.internet.protocol.DatagramProtocol.stopProtocol</a></code>
66
methods that will get called when the protocol is connected and
67
disconnected from a UDP socket.</p>
69
<p>The protocol's <code class="python">transport</code> attribute will
70
implement the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IUDPTransport.html" title="twisted.internet.interfaces.IUDPTransport">twisted.internet.interfaces.IUDPTransport</a></code> interface.
71
Notice that the <code class="python">host</code> argument should be an
72
IP, not a hostname. If you only have the hostname use <code class="python">reactor.resolve()</code> to resolve the address (see <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IReactorCore.resolve.html" title="twisted.internet.interfaces.IReactorCore.resolve">twisted.internet.interfaces.IReactorCore.resolve</a></code>).</p>
75
<h2>Connected UDP<a name="auto2"/></h2>
77
<p>A connected UDP socket is slighly different from a standard one - it
78
can only send and receive datagrams to/from a single address, but this
79
does not in any way imply a connection. Datagrams may still arrive in any
80
order, and the port on the other side may have no one listening. The
81
benefit of the connected UDP socket is that it it <strong>may</strong>
82
provide notification of undelivered packages. This depends on many
83
factors, almost all of which are out of the control of the application,
84
but it still presents certain benefits which occassionally make it
87
<p>Unlike a regular UDP protocol, we do not need to specify where to
88
send datagrams to, and are not told where they came from since
89
they can only come from address the socket is 'connected' to.</p>
91
<pre class="python"><p class="py-linenumber"> 1
112
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">DatagramProtocol</span>
113
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
115
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Helloer</span>(<span class="py-src-parameter">DatagramProtocol</span>):
117
<span class="py-src-keyword">def</span> <span class="py-src-identifier">startProtocol</span>(<span class="py-src-parameter">self</span>):
118
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">connect</span>(<span class="py-src-string">"192.168.1.1"</span>, <span class="py-src-number">1234</span>)
119
<span class="py-src-keyword">print</span> <span class="py-src-string">"we can only send to %s now"</span> % <span class="py-src-variable">str</span>((<span class="py-src-variable">host</span>, <span class="py-src-variable">port</span>))
120
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"hello"</span>) <span class="py-src-comment"># no need for address</span>
122
<span class="py-src-keyword">def</span> <span class="py-src-identifier">datagramReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">data</span>, (<span class="py-src-parameter">host</span>, <span class="py-src-parameter">port</span>)):
123
<span class="py-src-keyword">print</span> <span class="py-src-string">"received %r from %s:%d"</span> % (<span class="py-src-variable">data</span>, <span class="py-src-variable">host</span>, <span class="py-src-variable">port</span>)
125
<span class="py-src-comment"># Possibly invoked if there is no server listening on the</span>
126
<span class="py-src-comment"># address to which we are sending.</span>
127
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionRefused</span>(<span class="py-src-parameter">self</span>):
128
<span class="py-src-keyword">print</span> <span class="py-src-string">"No one listening"</span>
130
<span class="py-src-comment"># 0 means any port, we don't care in this case</span>
131
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenUDP</span>(<span class="py-src-number">0</span>, <span class="py-src-variable">Helloer</span>())
132
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
135
<p>Note that <code class="python">connect()</code>, like <code class="python">write()</code> will only accept IP addresses, not
136
unresolved domain names. To obtain the IP of a domain name use <code class="python">reactor.resolve()</code>, e.g.:</p>
138
<pre class="python"><p class="py-linenumber">1
144
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
146
<span class="py-src-keyword">def</span> <span class="py-src-identifier">gotIP</span>(<span class="py-src-parameter">ip</span>):
147
<span class="py-src-keyword">print</span> <span class="py-src-string">"IP of 'example.com' is"</span>, <span class="py-src-variable">ip</span>
149
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">resolve</span>(<span class="py-src-string">'example.com'</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">gotIP</span>)
152
<p>Connecting to a new address after a previous connection, or
153
making a connected port unconnected are not currently supported,
154
but will likely be supported in the future.</p>
156
<h2>Multicast UDP<a name="auto3"/></h2>
158
<p>A multicast UDP socket can send and receive datagrams from multiple clients.
159
The interesting and useful feature of the multicast is that a client can
160
contact multiple servers with a single packet, without knowing the specific IP
161
of any of the hosts.</p>
163
<div class="py-listing"><pre><p class="py-linenumber"> 1
188
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">DatagramProtocol</span>
189
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
190
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">MulticastServer</span>
192
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MulticastServerUDP</span>(<span class="py-src-parameter">DatagramProtocol</span>):
193
<span class="py-src-keyword">def</span> <span class="py-src-identifier">startProtocol</span>(<span class="py-src-parameter">self</span>):
194
<span class="py-src-keyword">print</span> <span class="py-src-string">'Started Listening'</span>
195
<span class="py-src-comment"># Join a specific multicast group, which is the IP we will respond to</span>
196
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">joinGroup</span>(<span class="py-src-string">'224.0.0.1'</span>)
198
<span class="py-src-keyword">def</span> <span class="py-src-identifier">datagramReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">datagram</span>, <span class="py-src-parameter">address</span>):
199
<span class="py-src-comment"># The uniqueID check is to ensure we only service requests from</span>
200
<span class="py-src-comment"># ourselves</span>
201
<span class="py-src-keyword">if</span> <span class="py-src-variable">datagram</span> == <span class="py-src-string">'UniqueID'</span>:
202
<span class="py-src-keyword">print</span> <span class="py-src-string">"Server Received:"</span> + <span class="py-src-variable">repr</span>(<span class="py-src-variable">datagram</span>)
203
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"data"</span>, <span class="py-src-variable">address</span>)
205
<span class="py-src-comment"># Note that the join function is picky about having a unique object</span>
206
<span class="py-src-comment"># on which to call join. To avoid using startProtocol, the following is</span>
207
<span class="py-src-comment"># sufficient:</span>
208
<span class="py-src-comment">#reactor.listenMulticast(8005, MulticastServerUDP()).join('224.0.0.1')</span>
210
<span class="py-src-comment"># Listen for multicast on 224.0.0.1:8005</span>
211
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenMulticast</span>(<span class="py-src-number">8005</span>, <span class="py-src-variable">MulticastServerUDP</span>())
212
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
213
</pre><div class="caption">Source listing - <a href="listings/udp/MulticastServer.py"><span class="filename">listings/udp/MulticastServer.py</span></a></div></div>
216
The server protocol is very simple, and closely resembles a normal listenUDP
217
implementation. The main difference is that instead of listenUDP,
218
listenMulticast is called with a specified port number. The server must also
219
call joinGroup to specify on which multicast IP address it will service
220
requests. Another item of interest is the contents of the datagram. Many
221
different applications use multicast as a way of device discovery, which leads
222
to an abundance of packets flying around. Checking the payload can ensure
223
that we only service requests from our specific clients.
226
<div class="py-listing"><pre><p class="py-linenumber"> 1
239
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">DatagramProtocol</span>
240
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
241
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">MulticastServer</span>
243
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MulticastClientUDP</span>(<span class="py-src-parameter">DatagramProtocol</span>):
245
<span class="py-src-keyword">def</span> <span class="py-src-identifier">datagramReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">datagram</span>, <span class="py-src-parameter">address</span>):
246
<span class="py-src-keyword">print</span> <span class="py-src-string">"Received:"</span> + <span class="py-src-variable">repr</span>(<span class="py-src-variable">datagram</span>)
248
<span class="py-src-comment"># Send multicast on 224.0.0.1:8005, on our dynamically allocated port</span>
249
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenUDP</span>(<span class="py-src-number">0</span>, <span class="py-src-variable">MulticastClientUDP</span>()).<span class="py-src-variable">write</span>(<span class="py-src-string">'UniqueID'</span>,
250
(<span class="py-src-string">'224.0.0.1'</span>, <span class="py-src-number">8005</span>))
251
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
252
</pre><div class="caption">MulticastServer.py - <a href="listings/udp/MulticastClient.py"><span class="filename">listings/udp/MulticastClient.py</span></a></div></div>
255
This is a mirror implementation of a standard UDP client. The only difference
256
is that the destination IP is the multicast address. This datagram will be
257
distributed to every server listening on 224.0.0.1 and port 8005. Note that
258
the client port is specified as 0, as we have no need to keep track of what
259
port the client is listening on.
262
<h2>Acknowledgements<a name="auto4"/></h2>
264
<p>Thank you to all contributors to this document, including:</p>
267
<li>Kyle Robertson, author of the explanation and examples of multicast</li>
272
<p><a href="index.html">Index</a></p>
273
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'