[Twisted-Python] How to send a UDP datagram

Drake Smith drakesmith at adelphia.net
Sat Sep 24 16:28:54 MDT 2005


>On Sat, 24 Sep 2005 11:33:50 -0400, Drake Smith <drakesmith at adelphia.net> 
>wrote:
>>Can somebody please show me the Twisted way to send a simple UDP 
>>datagram? From the examples, I see how to transport.write in response to 
>>receiving a datagram or in response to establishing a UDP "connection". 
>>But in my application, I'd like to send datagrams blindly, say, to 
>>initiate a heartbeat message or to stream audio samples without 
>>acknowledgement via an unconnected UDP socket. I'd also like to do this 
>>from a function that is not wrapped inside a Twisted protocol class as 
>>such, unless that is contrary to the Twisted approach.
>>
>>I am using Twisted version 2.0.1/Python 2.4 on a Linux box. Thank you.
>
>When a DatagramProtocol is hooked up to a transport, its startProtocol 
>method is invoked.  Here's how I'd write a heartbeat thingy:
>
>  from twisted.internet import protocol, reactor, task
>
>  class Heartbeat(protocol.DatagramProtocol):
>      def sendHeartbeat(self):
>          self.transport.write('poingo')
>
>      def startProtocol(self):
>          self._call = task.LoopingCall(self.sendHeartbeat)
>          self._loop = self._call.start(15)
>
>      def stopProtocol(self):
>          self._call.stop()
>
>  reactor.listenUDP(0, Heartbeat())
>  reactor.run()
>
>
>There's nothing particularly unique to Twisted if you want to turn this 
>inside out and have some other code controlling the loop, but here's an 
>example of that just for completeness:
>
>  from twisted.internet import protocol, reactor, task
>
>  class Heartbeat(protocol.DatagramProtocol):
>      def __init__(self, onStart):
>          self.onStart = onStart
>
>      def startProtocol(self):
>          self.onStart.callback(self)
>
>      def sendHeartbeat(self):
>          self.transport.write('poingo')
>
>  class HeartbeatSenderGuy(object):
>      def start(self):
>          d = defer.Deferred()
>          d.addCallback(self._listening)
>          self._port = reactor.listenUDP(0, Heartbeat(d))
>
>      def _listening(self, proto):
>          self._proto = proto
>          self._call = task.LoopingCall(self._proto.sendHeartbeat)
>          self._call.start(15)
>
>      def stop(self):
>          self._call.stop()
>          self._port.stopListening()
>
>  hb = HeartbeatSenderGuy()
>  hb.start()
>  reactor.run()
>
>Hope this helps,
>
>Jp


Jp,

Thank you for the extra effort to show us OO novices how to control the 
loop from outside the protocol class. I've read several inquiries to this 
effect but nobody has ever explained it.

I generalized your example to give me what I want: the ability to invoke 
UDP datagram messages from outside the protocol class:

from twisted.internet import protocol, reactor, defer

class UDPsender(protocol.DatagramProtocol):
     def __init__(self, onStart):
         self.onStart = onStart

     def startProtocol(self):
         self.onStart.callback(self)

     def sendMsg(self, data, (host, port)):
         self.transport.write(data, (host, port))

class DatagramSender(object):
     def start(self):
         d = defer.Deferred()
         d.addCallback(self._listening)
         self._port = reactor.listenUDP(0, UDPsender(d))

     def _listening(self, proto):
         global myProto
         myProto = proto

     def sendMsg(self, data, (host, port)):
         global myProto
         myProto.sendMsg(data, (host, port))

     def stop(self):
         self._call.stop()
         self._port.stopListening()

ds = DatagramSender()
ds.start()
ds.sendMsg("hello port 20006", ("127.0.0.1", 20006))
ds.sendMsg("hello port 20007", ("127.0.0.1", 20007))
reactor.run()

I tried a simpler implementation.....

from twisted.internet import protocol, reactor

class UDPsender(protocol.DatagramProtocol):

     def sendMsg(self, data, (host, port)):
         self.transport.write(data, (host, port))

ds = UDPsender()
ds.sendMsg("hello port 20006", ("127.0.0.1", 20006))
ds.sendMsg("hello port 20007", ("127.0.0.1", 20007))
reactor.run()

.....but I get the infamous "AttributeError: 'NoneType' object has no 
attribute 'write'" error. I'll stay with the former version. It's not 
exactly as compact as "mySocket.sendto(data, addr)" but I know it will 
cause me less headaches as my program evolves.

Jp: I see your name a lot within the Python community. Thanks for all your 
attentiveness to us new comers.



>_______________________________________________
>Twisted-Python mailing list
>Twisted-Python at twistedmatrix.com
>http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python





More information about the Twisted-Python mailing list