Repeating echo messages received over UDP over another TCP port

I am using Python 2.7.x (2.7.8) and trying to write a program using twisted python to work as follows:

  • The program expects to send messages over TCP 7001 or UDP 7000.
  • Messages received over UDP 7000 go to TCP 7001 output.

I could not understand how to connect UDP to TCP, so I looked at an example on this site, for example this Twisted UDP to TCP Bridge , but the problem is that the example lies because it does not work. I added a โ€œprint datagramโ€ to the datagramReceived to see if UDP responds to getting everything , and that is not the case. This is completely frustrating.

Here my current test code has changed a bit :

from twisted.internet.protocol import Protocol, Factory, DatagramProtocol from twisted.internet import reactor class TCPServer(Protocol): def connectionMade(self): self.port = reactor.listenUDP(7000, UDPServer(self)) def connectionLost(self, reason): self.port.stopListening() def dataReceived(self, data): print "Server said:", data class UDPServer(DatagramProtocol): def __init__(self, stream): self.stream = stream def datagramReceived(self, datagram, address): print datagram self.stream.transport.write(datagram) def main(): f = Factory() f.protocol = TCPServer reactor.listenTCP(7001, f) reactor.run() if __name__ == '__main__': main() 

As you can see, I changed the ports according to my test environment and added a print datagram to see if anything is calling datagramReceived. I have no problem sending TCP files to this program, TCPServer works just fine, because dataReceived is called.

+5
source share
2 answers

I ran the code from your question (with one small modification: I turned on logging). I used telnet to connect to a TCP server on port 7001. I used Python REPL to create a UDP socket and send some datagrams to port 7000.

Here is my transcript of REPL:

 >>> import socket >>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) >>> s.sendto('hello', ('127.0.0.1', 7000)) 5 >>> s.sendto('world', ('127.0.0.1', 7000)) 5 >>> 

Here is my server log (formatted on your screen):

 ... Log opened. ... Factory starting on 7001 ... Starting factory <twisted.internet.protocol.Factory instance at 0x2b9b128> ... UDPServer starting on 7000 ... Starting protocol <__main__.UDPServer instance at 0x2e8f8c0> ... hello ... world 

And here is my telnet session transcript:

 $ telnet localhost 7001 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. helloworld 

My interpretation of these results is that the program really works as directed. It is interesting that you did it differently when you tried it, which led to different, broken results.

+3
source

Here is a solution using the circuits Application Framework:

The code:

 #!/usr/bin/env python from circuits.net.events import write from circuits import handler, Component, Debugger from circuits.net.sockets import TCPServer, UDPServer class UDPTCPBroadcaster(Component): def init(self): self.clients = {} self.tcp = TCPServer(("0.0.0.0", 7001), channel="tcp").register(self) self.udp = UDPServer(("0.0.0.0", 7000), channel="udp").register(self) def broadcast(self, data, exclude=None): exclude = exclude or [] targets = (sock for sock in self.clients.keys() if sock not in exclude) for target in targets: self.fire(write(target, data), "tcp") @handler("connect", channel="tcp") def _on_tcp_connect(self, sock, host, port): self.clients[sock] = {"host": sock, "port": port} @handler("disconnect", channel="tcp") def _on_tcp_disconnect(self, sock): if sock not in self.clients: return del self.clients[sock] @handler("read", channel="tcp") def _on_tcp_read(self, sock, data): data = data.strip().decode("utf-8") print sock, data @handler("read", channel="udp") def _on_udp_read(self, peer, data): # Broadcast to all connected TCP clients self.broadcast(data) app = UDPTCPBroadcaster() Debugger().register(app) app.run() 

This does what you need, and here are the test results ...

Terminal # 1 Launch udptcpbroadcast.py :

 $ ./udptcpbroadcast.py <registered[tcp] (<TCPServer/tcp 31492:MainThread (queued=0) [S]>, <UDPTCPBroadcaster/* 31492:MainThread (queued=4) [R]> )> <registered[udp] (<UDPServer/udp 31492:MainThread (queued=0) [S]>, <UDPTCPBroadcaster/* 31492:MainThread (queued=5) [R]> )> <registered[*] (<Debugger/* 31492:MainThread (queued=0) [S]>, <UDPTCPBroadcaster/* 31492:MainThread (queued=5) [R]> )> <started[*] (<UDPTCPBroadcaster/* 31492:MainThread (queued=4) [R]> )> <registered[select] (<Select/select 31492:MainThread (queued=0) [S]>, <TCPServer/tcp 31492:MainThread (queued=0) [S]> )> <ready[tcp] (<TCPServer/tcp 31492:MainThread (queued=0) [S]>, ('0.0.0.0', 7001) )> <ready[udp] (<UDPServer/udp 31492:MainThread (queued=0) [S]>, ('0.0.0.0', 7000) )> <_read[udp] (<socket._socketobject object at 0x7f5645168c20> )> <read[udp] (('10.0.0.2', 35718), '\x00' )> <_read[tcp] (<socket._socketobject object at 0x7f5645168bb0> )> <connect[tcp] (<socket._socketobject object at 0x7f5645168c90>, '127.0.0.1', 57282 )> <_read[udp] (<socket._socketobject object at 0x7f5645168c20> )> <read[udp] (('10.0.0.2', 35718), 'Hello\n' )> <write[tcp] (<socket._socketobject object at 0x7f5645168c90>, 'Hello\n' )> <_write[tcp] (<socket._socketobject object at 0x7f5645168c90> )> ^C<signal[*] (2, <frame object at 0x1c38120> )> <stopped[*] (<UDPTCPBroadcaster/* 31492:MainThread (queued=0) [S]> )> <close[udp] ( )> <close[tcp] ( )> <closed[udp] ( )> <disconnect[udp] (<socket._socketobject object at 0x7f5645168c20> )> <disconnect[tcp] (<socket._socketobject object at 0x7f5645168bb0> )> <disconnect[tcp] (<socket._socketobject object at 0x7f5645168c90> )> <closed[tcp] ( )> 

Terminal No. 2 Sending a UDP message:

 $ ./telnet.py -u localhost 7000 Trying localhost ... Hello ^C 

Terminal # 3 Receiving UDP broadcast message:

 $ telnet localhost 7001 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello Connection closed by foreign host. 

Note: This is a biased answer / solution. I am the author of the schemes :) Perhaps if someone from the Twisted Community can respond using Twisted for comparison! Also note that the ./telnet.py tool comes directly from the sample circuits and is a telnet-like clone with support for both TCP and UDP.

Update: If you do not want to "broadcast" each connected client on a listening TCP server, you can change this behavior for the target connected clients. But it is up to you how you do it and manage it. (which client, how do we focus on them, etc.).

0
source

All Articles