Просмотр сервисов avahi с python пропускает сервисы
Мне нужен класс, который дает мне список служб avahi определенного типа, которые в настоящее время доступны. Поэтому я управляю gobject.MainLoop()
(строка 23-25) в отдельном потоке добавить браузер для каждой интересующей меня услуги (строка 27,28). Это работает в принципе.
Моя проблема в том, что я не всегда получаю все услуги. Иногда перечисляются все доступные службы, иногда нет ни одной, иногда несколько. Я предполагаю, что браузер начинает перебирать сервисы (строка 36) до того, как будут подключены соответствующие сигналы (строка 41-44), но я понятия не имею, как это исправить. Ниже приведен минимальный пример, который показывает сбой.
Большинство примеров, которые я видел в сети (например: Остановка службы 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()
1 ответ
Я не смог найти устанавливаемый пакет 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