目标是利用 Python 开发 Avahi 服务端和客户端应用,以在网络中广播服务可用性并进行服务查找。具体问题包括:
- 如何在 Python 中编写 Avahi 服务端程序,以便广播服务可用性?
- 如何在 Python 中编写 Avahi 客户端程序,以便搜索并发现可用的服务?
-
解决方案
为了解决上述问题,可以采取以下步骤:
-
服务端代码
import avahi import dbus class ZeroconfService: def __init__(self, name, port, stype="_http._tcp", domain="", host="", text=""): self.name = name self.stype = stype self.domain = domain self.host = host self.port = port self.text = text def publish(self): bus = dbus.SystemBus() server = dbus.Interface( bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) g = dbus.Interface( bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) g.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0), self.name, self.stype, self.domain, self.host, dbus.UInt16(self.port), self.text) g.Commit() self.group = g def unpublish(self): self.group.Reset() def test(): service = ZeroconfService(name="TestService", port=3000) service.publish() input("Press any key to unpublish the service ") service.unpublish() if __name__ == "__main__": test()只需要调用
service.publish()方法就可以发布服务了。 -
客户端代码
import dbus, gobject, avahi from dbus import DBusException from dbus.mainloop.glib import DBusGMainLoop TYPE = "_http._tcp" def service_resolved(*args): print('service resolved') print('name:', args[2]) print('address:', args[7]) print('port:', args[8]) def print_error(*args): print('error_handler') print(args[0]) def myhandler(interface, protocol, name, stype, domain, flags): print("Found service '%s' type '%s' domain '%s' " % (name, stype, domain)) if flags & avahi.LOOKUP_RESULT_LOCAL: # local service, skip pass server.ResolveService(interface, protocol, name, stype, domain, avahi.PROTO_UNSPEC, dbus.UInt32(0), reply_handler=service_resolved, error_handler=print_error) loop = DBusGMainLoop() bus = dbus.SystemBus(mainloop=loop) server = dbus.Interface(bus.get_object(avahi.DBUS_NAME, '/'), 'org.freedesktop.Avahi.Server') sbrowser = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.ServiceBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, TYPE, 'local', dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_BROWSER) sbrowser.connect_to_signal("ItemNew", myhandler) gobject.MainLoop().run()只需要调用
sbrowser对象的connect_to_signal()方法就可以监听服务查找事件,并在服务发现时触发回调函数myhandler()。
-