【问题标题】:How do I find out my multicast (Bonjour) hostname?如何找出我的多播 (Bonjour) 主机名?
【发布时间】:2013-08-16 10:43:26
【问题描述】:

我使用 Bonjour API 注册了一条记录。现在我想知道我刚刚发布的记录的内容。我通过指定一个 NULL 主机名来创建它,意思是“使用守护进程的默认值”,但我找不到一个简单的方法来查询它是什么!

使用 avahi,很容易:我调用 avahi_client_get_host_name() 来获取机器主机名的起始值。

对于 avahi 和 Bonjour,SRV 记录的值可以在注册的生命周期内更改 - 如果注册是使用 NULL 主机名完成的,则记录的主机名会在必要时自动更新。我想要的只是在我执行注册时获取主机名的 initial 值的方法。

请注意,在我的 Snow Leopard 测试机器上,默认的多播主机名与来自 gethostname(2) 的机器名称相同。

我能想到的四个解决方案:

  1. 在我的进程中获取主机名。它可能在某个地方。我对我的进程的内存转储进行了strings(3) 搜索,并在我的地址空间中找到了多播主机名的四个实例,但考虑到该名称用于其他用途,这可能是巧合。即使我所追求的字符串在我的进程中的某个地方,我也无法找到一个 API 来合理地检索它。
  2. 从守护程序查询主机名。可能有一些查询我可以通过 mach 端口发送到获取它的守护进程?我再也找不到 API 了。相关代码块在 mDNSResponder 的 uDNS.c 文件中,似乎没有通过 RPC 接口暴露。
  3. 我可以查找我注册的服务。不过,这可能会涉及一些网络流量,因此除非有某种保证不会发生,否则我不愿意这样做。
  4. 重新实现 uDNS.c 中的逻辑。它从以下组合中获取机器的主机名:

    • 动态 DNS 配置
    • 静态配置的多播主机名
    • 反向查找主接口的 IPv4 地址
    • 它特别不使用gethostname(2) 或等效项

    重新实现该逻辑似乎不可行。

目前,我倾向于进行查找以获取初始 SRV 注册的值,但这似乎并不理想。正确的解决方案是什么?

【问题讨论】:

  • 不知道有没有更好的方法,但是我认为#3不涉及网络流量,因为本地的mDNSResponder知道答案。对我来说,这似乎是最可靠的方法。
  • 竞争条件让我很恼火——如果守护进程检测到冲突,它将撤回记录,因此查找可能会产生流量(尽管几乎不可能)。不过还是可以忍受的。

标签: macos networking bonjour zeroconf mdns


【解决方案1】:

我需要这样做。您想使用 ConvertDomainNameToCString 宏(包含在 mDNSEmbeddedAPI.h 中),并且需要访问核心 mDNS 结构。

您可以通过以下方式获得已注册的确切 Bonjour/Zeroconf 主机名:

char szHostname[512];
extern mDNS m;

ConvertDomainNameToCString(&m.MulticastHostname, szHostname);

希望对你有帮助。

【讨论】:

  • 哎呀!那不是公共标头。这也是一个可疑的短符号名称 - 我在哪里可以找到这个符号?我刚刚链接了一个使用一些 mDNS 函数的测试应用程序,它从 /usr/lib/libSystem.B.dylib 获取符号。不出所料,核心系统库中没有像“_m”这样短的符号。您不是在与守护进程对话的客户端库中描述静态链接,是吗?
  • 就我而言,我有一个直接的 C 语言 Zeroconf 实现,其中 mDNS 服务在我的嵌入式设备上作为线程运行。核心 mDNS 结构的实例(在我的例子中简称为“m”)可用于我的代码。我现在看到您可能正在通过 dns_sd.h API 访问 Mac 或 PC 上的守护程序。在这种情况下,守护进程必须使用其 mDNS 对象注册初始主机名,然后将其修饰为带有“xx.local.”的 FQDN。初始主机名可能是服务名称的一部分,直到第一个句点 (.)。
  • 是的,这个问题明确与使用公共 Bonjour API (dns_sd.h) 的桌面应用程序有关。守护进程当然知道当前主机名是什么,但如果不进行服务查找,客户端似乎无法获得该信息。 SRV 记录的名称 (string-i-picked._http._tcp) 肯定不包含主机名 ("computer-name.local."),它是记录的内容。我认为在所有三个平台(Win、Mac、Solaris)上复制用于创建主机名的逻辑是最简单的方法。
【解决方案2】:

为了记录,我使用 (4),获取机器的配置以将守护程序正在使用的主机名汇总在一起,而无需查询它。

static char* getBonjourDefaultHost()
{
  char* rv = 0;
#ifdef __APPLE__
  CFStringRef name = SCDynamicStoreCopyLocalHostName(NULL);
  if (name) {
    int len = CFStringGetLength(name);
    rv = new char[len*4+1];
    CFStringGetCString(name, rv, len*4+1, kCFStringEncodingUTF8);
    CFRelease(name);
  }
  // This fallback is completely incorrect, but why should we care...
  // Mac does something crazy like <sysctl hw.model>-<MAC address>.
  if (!rv)
    rv = GetHostname(); // using gethostname(2)

#elif defined(WIN32)
  CHAR tmp[256+1];
  ULONG namelength = sizeof(tmp);
  DynamicFn<BOOL (WINAPI*)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD)>
    GetComputerNameExA_("Kernel32", "GetComputerNameExA");
  if (!GetComputerNameExA_.isValid() ||
      !(*GetComputerNameExA_)(ComputerNamePhysicalDnsHostname, tmp, &namelength))
    tmp[0] = 0;
  // Roughly correct; there's some obscure string cleaning mDNSResponder does
  // to tidy up funny international strings.
  rv = tmp[0] ? strdup(tmp) : strdup("My Computer");

#elif defined(__sun)
  // This is exactly correct! What a relief.
  rv = GetHostName();

#else
#error Must add platform mDNS daemon scheme
#endif
  return rv;
}

【讨论】:

    【解决方案3】:

    从命令行可以使用scutil 命令获取本地(Bonjour)主机名:

    scutil --get LocalHostName
    

    这可以通过SystemConfiguration 框架使用kSCPropNetLocalHostName 键以编程方式获得。

    【讨论】:

    • 这与我的答案相同 - 解决方案 (4),尝试重新创建 mDNS 守护程序使用的逻辑。守护进程使用 LocalHostName 作为它的首选 - 但当然不必设置它,在这种情况下会出现各种后备...
    • 好吧,虽然我认为显示命令行解决方案和相关 API/框架的信息很有用,因为不清楚使用哪一个。
    【解决方案4】:

    我知道这已经被回答了,但是我根据 Pierz 在他回答的后半部分所说的话,去看看如何使用 SystemConfiguration 框架来做到这一点。

    这就是我的工作,认为它可能会节省其他人在谷歌上搜索的时间: 在斯威夫特:

    import SystemConfiguration
    
        let store = SCDynamicStoreCreate(nil, "ipmenu" as CFString, nil, nil )
        if let hostNames = SCDynamicStoreCopyValue(store, "Setup:/Network/HostNames" as CFString){
            if let hostName:String = (hostNames[kSCPropNetLocalHostName]) as? String {
                print("Host name:\(hostName)")
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多