2

現在利用可能な特定のタイプの avahi サービスのリストを提供するクラスが必要です。そのためgobject.MainLoop()、別のスレッドで (行 23 ~ 25) を実行し、関心のある各サービスのブラウザーを追加します (行 27、28)。これは原則として機能します。

私の問題は、常にすべてのサービスを利用できるとは限らないことです。利用可能なすべてのサービスがリストされている場合もあれば、どれもリストされていない場合もあれば、一部だけがリストされている場合もあります。私の推測では、適切な信号が接続される前に (行 41 ~ 44)、ブラウザーがサービスの反復を開始する (行 36) と思いますが、これを修正する方法がわかりません。失敗を示す最小限の例を以下に示します。

私がネット上で見たほとんどの例 (例: Avahi サービスを停止して要素のリストを返す) は、ブラウザがセットアップされてシグナルが接続された後に MainLoop を実行します。「AllForNow」シグナルが受信されると、ループは終了します。ブラウザは実行し続けて、新しいサービスまたは削除されたサービスをリッスンする必要があるため、これは私にとってオプションではありません(ちなみに、これは信頼性が高く機能しますが、最初のクエリだけが問題です)。

#!/usr/bin/python
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import avahi
import gobject
import threading

gobject.threads_init()
dbus.mainloop.glib.threads_init()

class ZeroconfBrowser:
    def __init__(self):
        self.service_browsers = set()
        self.services = {}
        self.lock = threading.Lock()

        loop = DBusGMainLoop(set_as_default=True)
        self._bus = dbus.SystemBus(mainloop=loop)
        self.server = dbus.Interface(
                self._bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), 
                avahi.DBUS_INTERFACE_SERVER)

        thread = threading.Thread(target=gobject.MainLoop().run)
        thread.daemon = True
        thread.start()

        self.browse("_ssh._tcp")
        self.browse("_http._tcp")

    def browse(self, service):
        if service in self.service_browsers:
            return
        self.service_browsers.add(service)

        with self.lock:
            browser = dbus.Interface(self._bus.get_object(avahi.DBUS_NAME, 
                    self.server.ServiceBrowserNew(avahi.IF_UNSPEC, 
                            avahi.PROTO_UNSPEC, service, 'local', dbus.UInt32(0))),
                    avahi.DBUS_INTERFACE_SERVICE_BROWSER)

            browser.connect_to_signal("ItemNew", self.item_new)
            browser.connect_to_signal("ItemRemove", self.item_remove)
            browser.connect_to_signal("AllForNow", self.all_for_now)
            browser.connect_to_signal("Failure", self.failure)

    def resolved(self, interface, protocol, name, service, domain, host, 
            aprotocol, address, port, txt, flags):
        print "resolved", interface, protocol, name, service, domain, flags

    def failure(self, exception):
        print "Browse error:", exception

    def item_new(self, interface, protocol, name, stype, domain, flags):
        with self.lock:
            self.server.ResolveService(interface, protocol, name, stype,
                    domain, avahi.PROTO_UNSPEC, dbus.UInt32(0),
                    reply_handler=self.resolved, error_handler=self.resolve_error)

    def item_remove(self, interface, protocol, name, service, domain, flags):
        print "removed", interface, protocol, name, service, domain, flags

    def all_for_now(self):
        print "all for now"

    def resolve_error(self, *args, **kwargs):
        with self.lock:
            print "Resolve error:", args, kwargs

import time
def main():
    browser = ZeroconfBrowser()
    while True:
        time.sleep(3)
        for key, value in browser.services.items():
            print key, str(value)

if __name__ == '__main__':
    main()
4

1 に答える 1

0

インストール可能な python-dbus パッケージが見つかりませんでした。しかし、うまく機能するAvahiブラウザの例を見つけました-avahi.py

pip install python-tdbus

ソース

#!/usr/bin/env python
#
# This file is part of python-tdbus. Python-tdbus is free software
# available under the terms of the MIT license. See the file "LICENSE" that
# was provided together with this source file for the licensing terms.
#
# Copyright (c) 2012 the python-tdbus authors. See the file "AUTHORS" for a
# complete list.

# This example shows how to access Avahi on the D-BUS.


from tdbus import SimpleDBusConnection, DBUS_BUS_SYSTEM, DBusHandler, signal_handler, DBusError

import logging

logging.basicConfig(level=logging.DEBUG)

CONN_AVAHI = 'org.freedesktop.Avahi'
PATH_SERVER = '/'
IFACE_SERVER = 'org.freedesktop.Avahi.Server'

conn = SimpleDBusConnection(DBUS_BUS_SYSTEM)

try:
    result = conn.call_method(PATH_SERVER, 'GetVersionString',
                        interface=IFACE_SERVER, destination=CONN_AVAHI)
except DBusError:
    print 'Avahi NOT available.'
    raise

print 'Avahi is available at %s' % CONN_AVAHI
print 'Avahi version: %s' % result.get_args()[0]
print
print 'Browsing service types on domain: local'
print 'Press CTRL-c to exit'
print

result = conn.call_method('/', 'ServiceTypeBrowserNew', interface=IFACE_SERVER,
                    destination=CONN_AVAHI, format='iisu', args=(-1, 0, 'local', 0))
browser = result.get_args()[0]
print browser
class AvahiHandler(DBusHandler):

    @signal_handler()
    def ItemNew(self, message):
    args = message.get_args()
        print 'service %s exists on domain %s' % (args[2], args[3])

conn.add_handler(AvahiHandler())
conn.dispatch()

出力

Avahi is available at org.freedesktop.Avahi
Avahi version: avahi 0.6.31

Browsing service types on domain: local
Press CTRL-c to exit

/Client1/ServiceTypeBrowser1
service _udisks-ssh._tcp exists on domain local
service _workstation._tcp exists on domain local
service _workstation._tcp exists on domain local
service _udisks-ssh._tcp exists on domain local
于 2014-08-24T21:13:51.113 に答える