【Airplay_BCT】Bonjour API架构

news/2024/7/20 21:00:43 标签: 架构, ios, cocoa

Bonjour API 架构

OS X 和 iOS 为 Bonjour 服务应用程序提供了多层应用程序编程接口 (API): Foundation 框架中的 NSNetService 和 NSNetServiceBrowser 类; CFNetServices,Core Services 中 CFNetwork 框架的一部分; Java 的 DNS 服务发现(仅限 OS X);以及围绕 BSD 套接字构建的低级 DNS 服务发现 API。所有三个 API 集都为网络服务的发布、发现和解析提供便利。图 3-1 说明了 API 层的结构。如您所见,多播 DNS 响应程序(或其他 DNS 服务器)位于最低级别,因此您的软件不必直接与 DNS 交互。
在这里插入图片描述

NSNetService 和 NSNetServiceBrowser

NSNetService 和 NSNetServiceBrowser 类是 Cocoa 中基础框架的一部分,为服务发现和发布提供了面向对象的抽象。 NSNetService 对象表示 Bonjour 服务的实例,用于发布或由客户端发现的服务,而 NSNetServiceBrowser 表示用于特定类型服务的浏览器。大多数 Cocoa 程序员应该会发现这些类足以满足他们的需要。如果您需要更详细的控制,您可以使用来自 Cocoa 应用程序的 DNS 服务发现 API。

NSNetService 和 NSNetServiceBrowser 被调度在默认的 NSRunLoop 对象上,以异步方式执行发布、发现和解析。 NSNetService 和 NSNetServiceBrowser 对象返回的所有结果都由委托对象处理。这些对象必须与一个运行循环相关联才能运行,但它不必是默认的。

CFNet服务

Core Services 框架中声明的 CFNetServices API 提供了 Core Foundation 风格的类型和函数,用于管理服务和服务发现。 CFNetServices 定义了三种 Core Foundation 对象类型,CFNetService、CFNetServiceBrowser 和 CFNetServiceMonitor。 CFNetService 是服务实例的抽象表示,可用于发布或使用。关联函数为发布和解析服务提供支持。 CFNetServiceBrowser 表示特定域中特定类型服务的浏览器。通常只有在 OS X 或 iOS 的核心基础层编写代码时才应使用此 API。

CFNetService 和 CFNetServiceBrowser 对象通常在 CFRunLoops 中提供服务。为检索结果,应用程序实施回调函数来处理事件,例如新服务出现或消失、正在解析的实例以及发生的错误。与 NSNetService 和 NSNetServiceBrowser 不同,CFNetServices 类型不需要运行循环,并且可以在需要此行为时同步运行。但是,使用这些函数的同步模式是不好的做法。

DNS 服务发现

在 /usr/include/dns_sd.h 中声明的 DNS 服务发现 API 为 Bonjour 服务提供低级 BSD 套接字通信。 DNS 服务发现充当您的软件和多播 DNS 响应程序或 DNS 服务器之间的中间层。它为您管理多播 DNS 响应程序,让您根据服务和服务浏览器而不是 DNS 资源记录来编写程序。

因为 DNS 服务发现 API 是 Darwin 开源项目的一部分,所以您应该在编写跨平台代码(适用于 iOS 和 OS X 以外的平台)或需要使用更高版本中不可用的低级功能时使用它级 API,例如 NSNetService。

如果为 Windows、Linux 或 FreeBSD 开发 Bonjour 服务应用程序,DNS 服务发现也是应该使用的 API。


## Bonjour Operations

本章描述了作为三个网络服务 API 层和 API 层本身基础的服务发布、浏览和解析的 Bonjour 操作。如果你想编写一个发布或发现网络服务的应用程序或工具,你应该阅读本章。

架构概述

Bonjour 中的网络服务架构包括一个易于使用的机制,用于发布、发现和使用基于 IP 的服务。 Bonjour 支持三个基本操作,每个操作都是零配置网络服务的必要部分:

  1. 出版物(为服务做广告)
  2. 发现(浏览可用服务)
  3. 解析(将服务实例名称翻译成地址和端口号以供使用)

## 出版物

要发布服务,应用程序或设备必须通过高级 API 或直接与响应器 (mDNSResponder) 通信,向多播 DNS 响应器注册该服务。 Bonjour 还支持使用动态 DNS 更新在传统 DNS 服务器上存储记录。

注册服务时,会创建三个相关的 DNS 记录:服务 (SRV) 记录、指针 (PTR) 记录和文本 (TXT) 记录。 TXT 记录包含解析或使用服务所需的附加数据,尽管它通常也是空的。

服务记录

SRV 记录将服务实例的名称映射到客户端实际使用该服务所需的信息。然后,客户端将服务实例名称存储为访问服务的持久方式,并在需要连接时对主机名和端口号执行 DNS 查询。这种额外的间接级别提供了两个重要的特性。首先,该服务由人类可读的名称而不是域名和端口号来标识。其次,即使服务的端口号、IP 地址或主机名发生变化,只要服务名称保持不变,客户端也可以访问该服务。

SRV 记录包含两条信息来标识服务:

  1. 主机名
  2. 端口名

主机名是当前可以找到该服务的域名。给出主机名而不是单个 IP 地址的原因是它可能是具有多个 IP 地址的多宿主主机,或者它可能具有 IPv6 地址和 IPv4 地址,等等。通过名称识别主机可以优雅地处理所有这些情况。

端口号标识服务的 UDP 或 TCP 端口。

SRV 记录根据以下约定命名:

<Instance Name>.<Service Type>.<Domain>
<实例名称>.<服务类型>.<>

,服务实例的名称,可以是任何 UTF-8 编码的 Unicode 字符串,并且旨在供人类阅读。

是一个标准的 IP 协议名称,前面有一个下划线,后面是主机到主机的传输协议(TCP 或 UDP),前面也有一个下划线。例如,在 UDP 上运行的普通 FTP 服务将具有 _tftp._udp 服务类型,而在 TCP 上运行的 IPP 打印服务将在 _ipp._tcp 服务类型下注册。官方协议名称列表由 IANA 维护;有关详细信息,请参阅域命名约定。

是一个标准的 DNS 域。这可能是特定域,例如 apple.com.,或通用后缀 local。对于只能在本地链接上访问的服务。

以下是在 TCP 端口 515 上运行的名为 PrintsAlot 的后台打印程序的 SRV 记录示例(采用标准 DNS 记录格式):PrintsAlot._printer._tcp.local。 120 IN SRV 0 0 515 blackhawk.local。

该记录将在名为 blackhawk.local 的打印机的多播 DNS 响应器上创建。在本地链接上。初始 120 表示用于缓存的生存时间 (TTL) 值。两个零是权重和优先级值,在传统 DNS 中用于在与给定名称匹配的多个记录之间进行选择;对于多播 DNS,这些值将被忽略。

指针记录

PTR 记录通过将服务类型映射到该类型服务的特定实例的名称列表来启用服务发现。此记录添加了另一层间接寻址,因此只需查找标有服务类型的 PTR 记录即可找到服务。

该记录仅包含一条信息,即服务实例的名称(与 SRV 记录的名称相同)。 PTR 记录相应地命名为 SRV 记录,但没有实例名称:<Service Type>.<Domain>

以下是名为 PrintsAlot 的后台打印程序的 PTR 记录示例_printer._tcp.local。 28800 PTR PrintsAlot._printer._tcp.local。

同样,28800 是生存时间 (TTL) 值,以秒为单位。

文本记录

TXT 记录与对应的 SRV 记录同名,可以包含少量关于服务实例的附加信息,通常最多不超过 100-200 字节。此记录也可能为空。例如,网络游戏可以通告多人游戏中使用的地图名称,聊天程序可以通告用户的可用性(例如,闲置、离开或可用)。如果需要传输的数据量较大,主机应与客户端建立连接,直接发送数据。

从历史上看,此记录已用于在同一 IP 地址的同一端口上运行的多个服务,例如在同一打印服务器上运行的多个打印队列。在这种情况下,TXT 记录中的附加信息可用于识别预期的打印队列,如本例所示:

在这里插入图片描述这种做法是必要的,因为服务类型历来与众所周知的端口相关联。鼓励新的 Bonjour 协议的设计者在不同的动态分配的端口号上运行他们服务的每个实例,而不是试图在同一个众所周知的端口号上运行它们并使用额外的信息来指定客户端正在尝试交谈的实例到。

TXT 记录中数据的性质和格式是特定于每种服务类型的,因此每种新服务类型还需要为其关联的 TXT 记录(如果有)定义数据格式,并将此格式发布为协议规范。

例子

举一个具体的例子,假设有一个通过本地网络共享音乐的设备——支持 IP 的自动点唱机。假设它的传输协议是 TCP,它的应用协议名为 music。当有人将设备插入以太网集线器时,会发生许多事情,如图 4-1 所示。

在这里插入图片描述

在步骤 1 中,设备从 IPv4 链路本地范围 169.254.0.0 中随机选择子网掩码为 255.255.0.0 的链路本地 IP 地址 169.254.150.84,并将其公布到网络中。因为没有设备响应通知,所以设备将地址作为自己的地址。在第 2 步中,它启动自己的多播 DNS 响应程序,请求主机名 eds-musicbox.local.,验证其可用性,并将该名称作为自己的名称。接下来,在步骤 3 中,设备在 TCP 端口 1010 上启动音乐共享服务。最后,在步骤 4 中,它在本地以名称 Ed’s Party Mix 发布类型为 _music._tcp 的服务。域,首先确保不存在同名服务。这将创建两个记录:

  • 名为 Ed’s Party Mix._music._tcp.local 的 SRV 记录。指向 eds-musicbox.local。在 TCP 端口 1010 上
  • 名为 _music._tcp.local 的 PTR 记录。指向 Ed 的 Party Mix._music._tcp.local。服务。

注意:发布服务时,如果域名或服务名称不可用,没有接口的设备应选择一个新名称。遇到这种情况的应用软件应该呈现一个用户界面,通知用户该名称不可用,并允许用户选择一个不同的名称。


发现

服务发现利用在服务发布期间注册的 DNS 记录来查找特定类型服务的所有命名实例。为此,应用程序通常通过更高级别的 API 查询与服务类型(例如 _http._tcp)匹配的 PTR 记录。在每台设备上运行的多播 DNS 响应程序返回带有服务实例名称的 PTR 记录。

在这里插入图片描述

图 4-2 说明了浏览音乐共享服务的客户端应用程序。在第 1 步中,客户端应用程序发出对本地 _music._tcp 类型服务的查询。域到标准多播地址 224.0.0.251。网络上的每个多播 DNS 响应程序都会听到请求,但只有音乐共享设备会使用 PTR 记录进行响应(第 2 步)。生成的 PTR 记录包含服务实例名称 Ed’s Party Mix._music._tcp.local。在这种情况下。然后,客户端应用程序可以从 PTR 记录中提取服务实例名称,并将其添加到屏幕上的音乐服务器列表中。


解析

服务发现通常只偶尔发生一次——例如,当用户第一次选择打印机时。此操作保存服务实例名称,即任何给定服务实例的预期稳定标识符。端口号、IP 地址,甚至主机名每天都在变化,但用户不需要每次都重新选择打印机。因此,从服务名称到套接字信息的解析直到服务被实际使用时才会发生。

为了解析服务,应用程序使用服务名称执行 SRV 记录的 DNS 查找。多播 DNS 响应器使用包含当前信息的 SRV 记录进行响应。

图 4-3 说明了音乐共享示例中的服务解析。解析过程从向多播地址 224.0.0.251 请求 Ed’s Party Mix._music._tcp.local 的 DNS 查询开始。 SRV 记录(步骤 1)。在第 2 步中,此查询返回服务的主机名和端口号 (eds-musicbox.local., 1010)。在第 3 步中,客户端发出 IP 地址的多播请求。在第 4 步中,此请求解析为 IP 地址 169.254.150.84。然后客户端可以使用 IP 地址和端口号连接到服务。每次使用服务时都会发生此过程,因此总能找到服务的最新地址和端口号。


http://www.niftyadmin.cn/n/68551.html

相关文章

Scala 入门(第一章Scala 环境搭建、插件的安装)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 第 1 章 Scala 入门1.1 概述1.1.1 为什么学习 Scala1.1.2 Scala 发展历史1.1.3 Scala 和 Java 关系1.1.4 Scala 语言特点1.2 Scala 环境搭建1.3 Scala 插件安装1.4 HelloWorl…

elasticsearch之日期类型有点怪

一、Date类型简介 elasticsearch通过JSON格式来承载数据的&#xff0c;而JSON中是没有Date对应的数据类型的&#xff0c;但是elasticsearch可以通过以下三种方式处理JSON承载的Date数据 符合特定格式化的日期字符串&#xff1b;基于milliseconds-since-the-epoch的一个长整型…

【PyQt】树形控件QTreeWidget的复选框实现自动部分选择/半选择状态

为实现如下效果&#xff0c;搜索未得&#xff0c;自己总结。1 效果2 代码以下非完整代码&#xff0c;仅作演示用。2.1 引入包from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QMainWindow, QApplication, QTreeWidgetItem from PyQt5.uic import loadUi import sys2.…

mysql 截取字符串操作实现

mysql截取字符串的函数有left,right,substring,substring_index.下面是详细说明及示例&#xff1a; 1、从左开始截取字符串 left&#xff08;str, length&#xff09; 说明&#xff1a;left&#xff08;被截取字段&#xff0c;截取长度&#xff09; 例&#xff1a;select left&…

【力扣-LeetCode】LCP 07. 传递信息 C++题解

LCP 07. 传递信息难度简单248收藏分享切换为英文接收动态反馈小朋友 A 在和 ta 的小伙伴们玩传信息游戏&#xff0c;游戏规则如下&#xff1a;有 n 名玩家&#xff0c;所有玩家编号分别为 0 &#xff5e; n-1&#xff0c;其中小朋友 A 的编号为 0每个玩家都有固定的若干个可传信…

ESP-IDF:TCP多线程并发服务器

核心代码&#xff1a; 核心思想就是主线程只处理socket监听功能&#xff0c;把数据处理部分分配到不同的线程中去处理。来了一个客户端连接&#xff0c;就分配新的线程去处理该客户端的数据请求。 代码&#xff1a; /多线程并发服务器/ #include <stdio.h> #include …

中国国家级地面气象站基本气象要素日值数据集(V3.0)

数据集摘要 数据集包含了中国基本气象站、基准气候站、一般气象站在内的主要2474个站点1951年1月以来本站气压、气温、降水量、蒸发量、相对湿度、风向风速、日照时数和0cm地温要素的日值数据。数据量为21.3GB。 (1)SURF_CLI_CHN_MUL_DAY-TEM-12001-201501.TXT 气温数据TEM, 包…

C++学习笔记-环境设置

C 是一种通用编程语言&#xff0c;如今已广泛用于竞争性编程。它具有命令式&#xff0c;面向对象和通用编程功能。 C 在Windows&#xff0c;Linux&#xff0c;Unix&#xff0c;Mac等许多平台上运行。在开始使用C 进行编程之前。我们将需要在本地计算机上设置一个环境&#xff0…