Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flexible, Solid and Portable Service Discovery

I am looking for a way for clients in a LAN to find all the instances of my server application without any configuration. Instead of hacking something myself, I'd like to use an existing solution. Personally, I need it to be done in Python, but I'd happy to hear about solutions in any other language.

So why am I not using avahi or OpenSLP or some other Zeroconf/SLP solution? Well, there are a couple of additional criteria, and I'm under the impression neither of the aforementioned systems matches them.

I'm looking for a solution that is:

  • Flexible. It must not require superuser rights, i.e. only use ports>1024.
  • Solid. It must allow multiple services of the same and different service type on a single machine and continue advertising the services even when the instance that started the advertisement server stops or crashes.
  • Portable. It must run nearly everywhere, or at least on *BSD, Debian/gentoo/RedHat/SuSe Linux, Mac OS X, Solaris and Windows NT.
  • Light. Ideally, one Python script would be the whole solution. I'm not in the least interested in address autoconfiguration or something like that, although I'd begrudgingly accept a solution that has lots of features I don't need. Furthermore, any one-time setup is a strict no-no.

I expect something like this:

def registerService(service): # (type, port)
    if listen(multicast, someport):
        if fork() == child:
            services = [service]
            for q in queriesToMe():
                if q == DISCOVERY:
                    answer(filter(q.criteria, services))
                elif q == ADVERTISE and q.sender == "localhost":
                    services.append(q.service)
    else:
        advertiseAt("localhost", service)
like image 327
phihag Avatar asked Feb 20 '09 02:02

phihag


2 Answers

For node discovery in a LAN I've used Twisted and UDP Multicast. Hope it helps you too.

Link to the twisted documentation that explains how to do it: https://twistedmatrix.com/documents/current/core/howto/udp.html#auto3

Here is a basic implementation of a server/client based in the twisted's code. It answers itself if you run once, but all the checking code and extra features were removed in order to make it simpler to read.

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

class MulticastPingPong(DatagramProtocol):
    MULTICAST_ADDR = ('228.0.0.5', 8005)
    CMD_PING = "PING"
    CMD_PONG = "PONG"

    def startProtocol(self):
        """
        Called after protocol has started listening.
        """
        # Set the TTL>1 so multicast will cross router hops:
        self.transport.setTTL(5)
        # Join a specific multicast group:
        self.transport.joinGroup(self.MULTICAST_ADDR[0])

        self.send_alive()

    def send_alive(self):
        """
        Sends a multicast signal asking for clients.
        The receivers will reply if they want to be found.
        """
        self.transport.write(self.CMD_PING, self.MULTICAST_ADDR)

    def datagramReceived(self, datagram, address):
        print "Datagram %s received from %s" % (repr(datagram), repr(address))

        if datagram.startswith(self.CMD_PING):
            # someone publishes itself, we reply that we are here
            self.transport.write(self.CMD_PONG, address)
        elif datagram.startswith(self.CMD_PONG):
            # someone reply to our publish message
            print "Got client: ", address[0], address[1]


if __name__ == '__main__':
    reactor.listenMulticast(8005, MulticastPingPong(), listenMultiple=True)
    reactor.run()
like image 42
ivanalejandro0 Avatar answered Oct 28 '22 10:10

ivanalejandro0


I wrote an application/library (currently Python and CLI interface) that matches all these critera. It's called minusconf. Turns out forking is not even necessary.

like image 191
phihag Avatar answered Oct 28 '22 09:10

phihag