Hi all,
 

After reading the UDP Networking how-to I added interaction using UDP messages to my distributed application. One sub-application is UDP broadcaster and the other one is responder.

Their minimized code is below:

 

broadcaster.py:

from datetime import datetime

import socket

import traceback

 

from twisted.internet import task, reactor

from twisted.internet.protocol import DatagramProtocol

 

DEFAULT_PORT = 2017

DEFAULT_HOST = "192.168.2.255"

DEFAULT_INTERVAL_SECONDS = 1

 

class BroadcasterProtocol(DatagramProtocol):

   def __init__(self, port):

       self._port = port

 

   def startProtocol(self):

       print "BroadcasterProtocol::startProtocol"

       self.transport.setBroadcastAllowed(True)

 

   def broadcastTime(self):

       time_str = datetime.now().time().strftime("%H:%M:%S.%f")

       try:

           self.transport.write(time_str.encode('utf-8'), ('<broadcast>', self._port))

           print "BroadcasterProtocol: broadcasted time: {}".format(time_str)

       except Exception:

           print "BroadcasterProtocol: time sending failed!"

 

   def datagramReceived(self, datagram, addr):

       print "BroadcasterProtocol: datagram from {} received:\n{}".format(addr, datagram)

 

def loopDone(unused):

   print "Loop done"

 

def loopFailure(failure):

   print "Loop failure! Failure is {}".format(traceback.format_exc(failure))

   

protocol = BroadcasterProtocol(DEFAULT_PORT)

the_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)

the_socket.setblocking(False)

the_socket.bind((DEFAULT_HOST, DEFAULT_PORT))

twisted_port = reactor.adoptDatagramPort(the_socket.fileno(), socket.AF_INET, protocol)

loop = task.LoopingCall(protocol.broadcastTime)

d = loop.start(DEFAULT_INTERVAL_SECONDS)

d.addCallback(loopDone).addErrback(loopFailure)

reactor.run()


responder.py:

from twisted.internet import reactor

from twisted.internet.protocol import DatagramProtocol

 

DEFAULT_PORT = 2017

 

class ResponderProtocol(DatagramProtocol):

   def datagramReceived(self, data, addr):

       print "ResponderProtocol: received from {addr}:\n{data}".format(

           addr = addr, data = data)

       response = "GOT " + data

       print "ResponderProtocol: sending response \"{response}\" to address {addr}".format(

           response = response, addr = addr)

       self.transport.write(response, addr)

 

responder_port = reactor.listenUDP(DEFAULT_PORT, ResponderProtocol())

reactor.run()

 

There are some reasons why I implemented UDP broadcasting and responding in the way that is a bit different than that shown in the official udpbroadcast.py example, but after reading UDP Networking how-to I thought this isn’t important.

ResponderProtocol.datagramReceived is successfully called with messages sent by broadcaster. Also I expected BroadcasterProtocol.datagramReceived to be called with “GOT <time>” responses sent by ResponderProtocol, but this doesn’t take place. Using strace I can see that sendto system function is being called by the responder process with “GOT <time>” messages, but there are no corresponding recv* calls in the broadcaster process.

Is this a bug or I made something wrong?

 
-- 
Kind regards, Roman Mescheryakov