Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Twisted Python: UDP Broadcast (simple echo server)

Tags:

python

twisted

I'm trying to adapt the Python Twisted - UDP examples to use UDP broadcast. I can send a message from the client and receive it on the server, however, it isn't sending a message back.

Client:

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

from socket import SOL_SOCKET, SO_BROADCAST

class EchoClientDatagramProtocol(DatagramProtocol):
    strings = [
        "Hello, world!",
        "What a fine day it is.",
        "Bye-bye!"
    ]

    def startProtocol(self):
        self.transport.socket.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
        self.transport.connect("255.255.255.255", 8000)
        self.sendDatagram()

    def sendDatagram(self):
        if len(self.strings):
            datagram = self.strings.pop(0)
            self.transport.write(datagram)
        else:
            reactor.stop()

    def datagramReceived(self, datagram, host):
        print 'Datagram received: ', repr(datagram)
        self.sendDatagram()

def main():
    protocol = EchoClientDatagramProtocol()
    #0 means any port
    t = reactor.listenUDP(0, protocol)
    reactor.run()

if __name__ == '__main__':
   main()

Server:

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class EchoUDP(DatagramProtocol):
    def datagramReceived(self, datagram, address):
        print "Received from address: " + str(address)
        print str(datagram)
        self.transport.write(datagram, address)
        print "Finished sending reply."

print "Starting server."
reactor.listenUDP(8000, EchoUDP())
reactor.run()

Console Output:

Server:

Starting server.
Received from address ('192.168.1.137', 53737)
Hello, world!
Finished sending reply.

Client:

no output.
like image 852
firefly2442 Avatar asked Oct 20 '22 14:10

firefly2442


1 Answers

transport.connect creates a connected UDP socket

A connected UDP socket is slightly different from a standard one - it can only send and receive datagrams to/from a single address, but this does not in any way imply a connection. Datagrams may still arrive in any order, and the port on the other side may have no one listening. The benefit of the connected UDP socket is that it it may provide notification of undelivered packages. This depends on many factors, almost all of which are out of the control of the application, but it still presents certain benefits which occasionally make it useful.

I suspect that the response from the server is not being caught by the client as it is listening for responses from the broadcast address, not the specific address of the server.

Instead, just use the self.transport.write(data, (host, port)) form of write without initiating the connection first - this will allow the client to receive packets from any address.

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

from socket import SOL_SOCKET, SO_BROADCAST

class EchoClientDatagramProtocol(DatagramProtocol):
    strings = [
        "Hello, world!",
        "What a fine day it is.",
        "Bye-bye!"
    ]

    def startProtocol(self):
        self.transport.socket.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
        #self.transport.connect("255.255.255.255", 8000) <- not needed
        self.sendDatagram()

    def sendDatagram(self):
        if len(self.strings):
            datagram = self.strings.pop(0)
            self.transport.write(datagram, ('255.255.255.255', 8000)) # <- write to broadcast address here
        else:
            reactor.stop()

    def datagramReceived(self, datagram, host):
        print 'Datagram received: ', repr(datagram)
        self.sendDatagram()

def main():
    protocol = EchoClientDatagramProtocol()
    #0 means any port
    t = reactor.listenUDP(0, protocol)
    reactor.run()


if __name__ == '__main__':
   main()
like image 173
Peter Gibson Avatar answered Oct 23 '22 03:10

Peter Gibson