Simplest way to publish over Zeroconf/Bonjour?

Question:

I’ve got some apps I would like to make visible with zeroconf.

  1. Is there an easy scriptable way to do this?
  2. Is there anything that needs to be done by my network admin to enable this?

Python or sh would be preferrable. OS-specific suggestions welcome for Linux and OS X.

Asked By: Mark Harrison

||

Answers:

Through the Avahi Python bindings, it’s very easy.

Answered By: jldupont

I’d recommend pybonjour.

Answered By: Alex Martelli

Or you can just use bash:

dns-sd -R <Name> <Type> <Domain> <Port> [<TXT>...]

This works by default on OS X. For other *nixes, refer to the avahi-publish man page (which you may need to install via your preferred package manager).

Answered By: Zack

pybonjour doesn’t seem to be actively maintained. I’m using python-zeroconf.

pip install zeroconf

Here is an excerpt from a script I use to announce a Twisted-Autobahn WebSocket to an iOS device:

from zeroconf import ServiceInfo, Zeroconf

class WebSocketManager(service.Service, object):
    ws_service_name = 'Verasonics WebSocket'
    wsPort = None
    wsInfo = None

    def __init__(self, factory, portCallback):
        factory.protocol = BroadcastServerProtocol
        self.factory = factory
        self.portCallback = portCallback
        self.zeroconf = Zeroconf()

    def privilegedStartService(self):
        self.wsPort = reactor.listenTCP(0, self.factory)
        port = self.wsPort.getHost().port

        fqdn = socket.gethostname()
        ip_addr = socket.gethostbyname(fqdn)
        hostname = fqdn.split('.')[0]

        wsDesc = {'service': 'Verasonics Frame', 'version': '1.0.0'}
        self.wsInfo = ServiceInfo('_verasonics-ws._tcp.local.',
                                  hostname + ' ' + self.ws_service_name + '._verasonics-ws._tcp.local.',
                                  socket.inet_aton(ip_addr), port, 0, 0,
                                  wsDesc, hostname + '.local.')
        self.zeroconf.register_service(self.wsInfo)
        self.portCallback(port)

        return super(WebSocketManager, self).privilegedStartService()

    def stopService(self):
        self.zeroconf.unregister_service(self.wsInfo)

        self.wsPort.stopListening()
        return super(WebSocketManager , self).stopService()

EDIT 2022-02-27: I’m not 100% sure anymore what I wrote is actually correct. I tried it recently and although it ran, I couldn’t get the info back through mdns query; suggesting that mDNS is possibly more complex than expected….. To be continued…. And please leave a comment if this does/does not work for you.


Although this answer points you in the right direction, it seems that python-zeroconf (0.39.4) had some changes making the example above not work (for me) anymore.

Also I think a more minimal, self-contained, answer would be nice, so here goes:

from zeroconf import ServiceInfo, Zeroconf

PORT=8080

zeroconf = Zeroconf()
wsInfo = ServiceInfo('_http._tcp.local.',
                     "myhost._http._tcp.local.",
                     PORT, 0, 0, {"random_key": "1234", "answer": "42"})
zeroconf.register_service(wsInfo)

import time
time.sleep(1000);

Note that anything beyond PORT is optional for ServiceInfo().

You can run multiple of these programs at the same time; they will all bind to the same UDP port without a problem.

Answered By: Claude
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.