Recently I've taken my first stab at Twisted/Python building an app that echoes incoming UDP strings out the TCP port. I assumed this would be very simple, but I haven't been able to get it to work. The code below is the example TCP & UDP Server modified to run together. I'm just trying to pass some data between the two. Any help would be appreciated.
from twisted.internet.protocol import Protocol, Factory, DatagramProtocol
from twisted.internet import reactor
class TCPServer(Protocol):
def dataReceived(self, data):
self.transport.write(data)
class UDPServer(DatagramProtocol):
def datagramReceived(self, datagram, address):
#This is where I would like the TCPServer's dataReceived method run passing "datagram". I've tried:
TCPServer.dataReceived(datagram)
#But of course that is not the correct call because UDPServer doesn't recognize "dataReceived"
def main():
f = Factory()
f.protocol = TCPServer
reactor.listenTCP(8000, f)
reactor.listenUDP(8000, UDPServer())
reactor.run()
if __name__ == '__main__':
main()
This is essentially the frequently asked How do I make input on one connection result in output on another?
The UDP<->TCP specifics in this question don't break the general answer given in the FAQ entry. Just notice that a DatagramProtocol
is easier to work with than a Protocol
because you already have the DatagramProtocol
instance without having to get the cooperation of a factory as you do in the Protocol
case.
Put another way:
from twisted.internet.protocol import Protocol, Factory, DatagramProtocol
from twisted.internet import reactor
class TCPServer(Protocol):
def connectionMade(self):
self.port = reactor.listenUDP(8000, UDPServer(self))
def connectionLost(self, reason):
self.port.stopListening()
class UDPServer(DatagramProtocol):
def __init__(self, stream):
self.stream = stream
def datagramReceived(self, datagram, address):
self.stream.transport.write(datagram)
def main():
f = Factory()
f.protocol = TCPServer
reactor.listenTCP(8000, f)
reactor.run()
if __name__ == '__main__':
main()
Notice the essential change: UDPServer
needs to call a method on an instance of TCPServer
so it needs a reference to that instance. This is achieved by making the TCPServer
instance pass itself to the UDPServer
initializer and making the UDPServer
initializer save that reference as an attribute of the UDPServer
instance.