利用 Python 实现 Avahi 服务端和客户端应用

70 阅读1分钟

目标是利用 Python 开发 Avahi 服务端和客户端应用,以在网络中广播服务可用性并进行服务查找。具体问题包括:

  • 如何在 Python 中编写 Avahi 服务端程序,以便广播服务可用性?
  • 如何在 Python 中编写 Avahi 客户端程序,以便搜索并发现可用的服务?
  1. 解决方案

    为了解决上述问题,可以采取以下步骤:

    1. 服务端代码

      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() 方法就可以发布服务了。

    2. 客户端代码

      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()