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):
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.).