[Twisted-Python] Transfering a transport between DatagramProtocols
![](https://secure.gravatar.com/avatar/c2282306ddf404a11cb66eb3674ab2d3.jpg?s=120&d=mm&r=g)
I am implementing a protocol where a DatagramProtocol "handshaking" subclass get an arbitrary port (by calling "self.udpPort = reactor.listenUDP(0, self)") and communicate it to a remote host. Once this is done, I would like to "switch" to another DatagramProtocol which would use the same port. To avoid a race condition, I would like to "transfert" self.transport from the first DatagramProtocol to the second without calling self.udpPort.stopListening(). Is this the "twisted" way to analyse this? Or should I use some kind of "proxy" DatagramProtocol which would relay datagramReceived calls to the proper DatagramProtocol, depending on the current protocol state (handshaking or data exchange)? Regards.
![](https://secure.gravatar.com/avatar/e1554622707bedd9202884900430b838.jpg?s=120&d=mm&r=g)
On Nov 24, 2009, at 4:26 PM, Olivier Parisy wrote:
Currently, the right way to do this is to do as you suggest, and have two DatagramProtocol instances, and a third which switches between them. Now, it just so happens that there is an accidental feature of udp.Port, whereby you can do self.udpPort.protocol = someOtherProtocol, and it will work. However, this feature is not supported and may break in a future version of Twisted. In the future, however, it would be reasonable and useful to have an explicit "switch protocol" method, which would tear down one protocol/transport relationship and set up another. If you would like to open a ticket and contribute a patch to do this, that would be great :).
![](https://secure.gravatar.com/avatar/c2282306ddf404a11cb66eb3674ab2d3.jpg?s=120&d=mm&r=g)
Glyph Lefkowitz a écrit :
OK, that seems like a reasonable pattern. Thanks for the confirmation.
I am not sure I would know where to start :-) But I'll give a look to DatagramProtocol source code. Regards, Olivier.
![](https://secure.gravatar.com/avatar/c2282306ddf404a11cb66eb3674ab2d3.jpg?s=120&d=mm&r=g)
Glyph Lefkowitz a écrit :
I tried to implement such a "switching" class so that I could freely change the DatagramProtocol handling a given port without releasing it. It is typically used in the following way : self.protocol = DelegatingDatagramProtocol(MyFirstDatagramProtocol()) self.udpPort = reactor.listenUDP(0, self.protocol) Then, later in the code : self.protocol.switchProtocol(MySecondDatagramProtocol()) Here is my current implementation : # Breaks when inheriting from DatagramProtocol? class DelegatingDatagramProtocol: def __init__(self, protocol): self._protocol = protocol def switchProtocol(self, protocol): self._protocol = protocol protocol.transport = self.transport def makeConnection(self, transport): self._protocol.makeConnection(transport) # Needed by switchProtocol self.transport = transport # Avoid an AssertionError (protocol.py:527 assert self.numPorts > 0) def doStop(self): pass # See http://www.python.org/workshops/1997-10/proceedings/savikko.html (Proxy pattern) def __getattr__(self, name): print 'Delegating to protocol: %s' % name return getattr(self._protocol, name) It mostly works, but I have two issues with it : - When doStop() is called by the reactor, an AssertionError is raised. I suppose this is due to my "sharing" of the transport in switchProtocol (which ensures that "transport.write" calls are directed to the proper transport), but how can I fix it? - If my class extends DatagramProtocol, it stops working (transport.write calls seems honored, then nothing works... I suppose datagramReceived is never called). Why is it so? Regards, Olivier.
![](https://secure.gravatar.com/avatar/e1554622707bedd9202884900430b838.jpg?s=120&d=mm&r=g)
On Nov 24, 2009, at 4:26 PM, Olivier Parisy wrote:
Currently, the right way to do this is to do as you suggest, and have two DatagramProtocol instances, and a third which switches between them. Now, it just so happens that there is an accidental feature of udp.Port, whereby you can do self.udpPort.protocol = someOtherProtocol, and it will work. However, this feature is not supported and may break in a future version of Twisted. In the future, however, it would be reasonable and useful to have an explicit "switch protocol" method, which would tear down one protocol/transport relationship and set up another. If you would like to open a ticket and contribute a patch to do this, that would be great :).
![](https://secure.gravatar.com/avatar/c2282306ddf404a11cb66eb3674ab2d3.jpg?s=120&d=mm&r=g)
Glyph Lefkowitz a écrit :
OK, that seems like a reasonable pattern. Thanks for the confirmation.
I am not sure I would know where to start :-) But I'll give a look to DatagramProtocol source code. Regards, Olivier.
![](https://secure.gravatar.com/avatar/c2282306ddf404a11cb66eb3674ab2d3.jpg?s=120&d=mm&r=g)
Glyph Lefkowitz a écrit :
I tried to implement such a "switching" class so that I could freely change the DatagramProtocol handling a given port without releasing it. It is typically used in the following way : self.protocol = DelegatingDatagramProtocol(MyFirstDatagramProtocol()) self.udpPort = reactor.listenUDP(0, self.protocol) Then, later in the code : self.protocol.switchProtocol(MySecondDatagramProtocol()) Here is my current implementation : # Breaks when inheriting from DatagramProtocol? class DelegatingDatagramProtocol: def __init__(self, protocol): self._protocol = protocol def switchProtocol(self, protocol): self._protocol = protocol protocol.transport = self.transport def makeConnection(self, transport): self._protocol.makeConnection(transport) # Needed by switchProtocol self.transport = transport # Avoid an AssertionError (protocol.py:527 assert self.numPorts > 0) def doStop(self): pass # See http://www.python.org/workshops/1997-10/proceedings/savikko.html (Proxy pattern) def __getattr__(self, name): print 'Delegating to protocol: %s' % name return getattr(self._protocol, name) It mostly works, but I have two issues with it : - When doStop() is called by the reactor, an AssertionError is raised. I suppose this is due to my "sharing" of the transport in switchProtocol (which ensures that "transport.write" calls are directed to the proper transport), but how can I fix it? - If my class extends DatagramProtocol, it stops working (transport.write calls seems honored, then nothing works... I suppose datagramReceived is never called). Why is it so? Regards, Olivier.
participants (2)
-
Glyph Lefkowitz
-
Olivier Parisy