Bonjour

article/2025/7/26 21:46:54

Bonjour 是苹果的一套零配置网络协议,用于发现局域网内的其他设备并进行通信,比如发现打印机、手机、电视等。

一句话:发现局域网其他设备和让其他设备发现。

Bonjour 可以完成的工作

  • IP 获取
  • 名称解析
  • 搜索服务

2048

实际应用场景示例,HomeKit/Matter 智能设备入网后,需要通过 Bonjour 来发现设备,获取 ip,进行 http 局域网通信,获取只能设备信息,绑定用户账号等。

权限要求

Bonjour 功能需要在info.plist 开启本地网络,和指定 services。

截屏2022-02-25 下午3.17.41

Tips: _hap._tcp遵循了 HAP(HomeKie Accessory Protocol) 智能家居协议的硬件,会在这个服务发送数据。

类似的,Matter 配件使用服务类型为_matter._tcp

检测本地网络是否权限是否开启

苹果并没有提供本地网络权限回调和查询,所有我们并不知道用户是否拒绝了本地网络权限。

可以在StackOverflow的How to check local network permission in iOS14,iOS 14 How to trigger Local Network dialog and check user answer?中找到检测代码,还是有效的。

Bonjour 扫描服务

通过 Bonjour 发现设备的实现分为以下情况

iOS2.0 - 15.0: NSNetServiceBrowser

iOS13.0+: NWBrowser (暂不知解析 ip 方式)

虽然按照苹果的习惯,被标记过期的接口,在未来很长时间都可以使用。但是也说明苹果提供了其他方式(NWBrowser)来实现 Bonjour

流程

先搜索服务,再连接服务,最后解析ip等信息。

NSNetserviceBrowser

在 iOS2.0到 iOS15.0系统中,Bonjour 可与通过 Foundation -> Bonjour 框架中的 NetserviceBrowser 来实现扫描和服务处理。

示例代码

开始扫描

@property (nonatomic, strong) NSNetServiceBrowser *brower;- (void)startSearch {//[self.services removeAllObjects];//[self.scanDevices removeAllObjects];self.brower = [[NSNetServiceBrowser alloc] init];self.brower.delegate = self;[self.brower stop];[self.brower searchForServicesOfType:@"_hap._tcp" inDomain:@"local."];
}

NetServiceBrowserDelegate代理

/* * 即将查找服务*/
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser {NSLog(@"-----------------netServiceBrowserWillSearch");
}/* * 停止查找服务*/
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser {NSLog(@"-----------------netServiceBrowserDidStopSearch");
}/* * 查找服务失败*/
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didNotSearch:(NSDictionary<NSString *, NSNumber *> *)errorDict {NSLog(@"----------------netServiceBrowser didNotSearch");
}/** 发现域名服务*/
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing {NSLog(@"---------------netServiceBrowser didFindDomain");// 过滤服务 添加到数组中(避免服务被释放,不走代理),连接服务[self.services addObject:service];//此处添加为了避免sevice被过早释放,不走代理方法service.delegate = self;//解析服务[service resolveWithTimeout:5];
}/* * 发现客户端服务*/
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {NSLog(@"didFindService---------=%@  =%@  =%@",service.name,service.addresses,service.hostName);[aNetService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];aNetService.delegate = self;[aNetService resolveWithTimeout:6];CFRunLoopRun();}/* * 域名服务移除*/
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didRemoveDomain:(NSString *)domainString moreComing:(BOOL)moreComing {NSLog(@"---------------netServiceBrowser didRemoveDomain");   
}/* * 客户端服务移除*/
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didRemoveService:(NSNetService *)service moreComing:(BOOL)moreComing {NSLog(@"---------------netServiceBrowser didRemoveService");
}

NSNetserviceDelegate

- (void)netServiceDidResolveAddress:(NSNetService *)sender{// 连接到服务,可以从 sender 中获取网络信息 比如 ip4 ip6 port 等// 进行数据通信,比如 http数据交互}

停止扫描

在业务中应该在一段时间后或者触发某些情况下关闭扫描,避免一致扫描。

[self.brower stop];

从 NSNetservice中解析网络数据

- (NSDictionary *)parsingIP:(NSNetService *)sender{int sPort = 0;NSString *ipv4;NSString *ipv6;for (NSData *address in [sender addresses]) {typedef union {struct sockaddr sa;struct sockaddr_in ipv4;struct sockaddr_in6 ipv6;} ip_socket_address;struct sockaddr *socketAddr = (struct sockaddr*)[address bytes];if(socketAddr->sa_family == AF_INET) {sPort = ntohs(((struct sockaddr_in *)socketAddr)->sin_port);struct sockaddr_in* pV4Addr = (struct sockaddr_in*)socketAddr;int ipAddr = pV4Addr->sin_addr.s_addr;char str[INET_ADDRSTRLEN];ipv4 = [NSString stringWithUTF8String:inet_ntop( AF_INET, &ipAddr, str, INET_ADDRSTRLEN )];}else if(socketAddr->sa_family == AF_INET6) {sPort = ntohs(((struct sockaddr_in6 *)socketAddr)->sin6_port);struct sockaddr_in6* pV6Addr = (struct sockaddr_in6*)socketAddr;char str[INET6_ADDRSTRLEN];ipv6 = [NSString stringWithUTF8String:inet_ntop( AF_INET6, &pV6Addr->sin6_addr, str, INET6_ADDRSTRLEN )];}else {NSLog(@"Socket Family neither IPv4 or IPv6, can't handle...");}}NSDictionary *data = @{@"type": [sender type],@"domain": [sender domain],@"name": [sender name],@"ipv4": ipv4,@"ipv6": ipv6,@"port": [NSNumber numberWithInt:sPort]};return data;
}

NWBrowser

在iOS13+在NetWork 框架中提供了 NWBrowser 类来实现 Bonjour,且只支持 Swfit.

示例代码

import Foundation
import Network
@available(iOS 13.0, *)
@objc
class BonjourManager: NSObject {@objcstatic let shared = BonjourManager()let browser = NWBrowser(for: .bonjourWithTXTRecord(type:"_hap._tcp", domain: ""), using: NWParameters())/// 搜索, 先搜索,再连接,才能解析到网络信息@objcfunc start() {browser.browseResultsChangedHandler = { (results, changes) inprint("Results:")for result in results // 建议存在数组中,注意去重{if case .service(let name,let type,let domain,let interface) = result.endpoint{// Bonjour ServicedebugPrint("Bonjour设备:\(name)")// 条件过滤let connection = NWConnection(to: result.endpoint, using: .tcp)connection.stateUpdateHandler = { state inswitch state {case .ready:if let innerEndpoint = connection.currentPath?.remoteEndpoint, case .hostPort(let host, let port) = innerEndpoint, case .ipv4(let ip4) = host {switch host {case .ipv4( let ip4):print("Bonjour \(name) ip4:\(ip4.debugDescription)")case .ipv6(let ip6):print("Bonjour ip6:\(ip6.debugDescription)")default:print("Bonjour host:\(host.debugDescription)")}}default :break}// 断开连接 connection.cancel()}connection.start(queue: .main)} else if case .hostPort(let host, let port) = result.endpoint {debugPrint("\(host)")}else{assert(false, "This nevers gets executed")}}//            print("Changes:")////            for change in changes//            {//                if case .added(let added) = change//                {//                    if case .service(let service) = added.endpoint//                    {//                        debugPrint(service)//                    }//                    else//                    {//                        assert(false, "This nevers gets executed")//                    }//                }//            }}browser.start(queue: .main)}/// 取消@objcfunc cancel() {browser.cancel()}
}

参考

官方资料

Support local network privacy in app

WWDC2020视频资料,介绍为什么需要本地网络权限,怎么设置权限,什么情况下可以不使用访问本地网络,而使用其他技术。其中以Boujour技术举例对本地网络权限的使用。

如何在你的 App 中使用组播网络

通过组播网络查看其他设备和通信。

组播在其他平台可能称为:组播DNS、mDNS 或者 DNS 服务发现

介绍本地网络权限和 Boujour info.plist 配置。以及如何利用 NWConnectionGroup 进行组播数据发送与接收。

如何获取 NWEndpoint 的 ip 信息 – stackoverflow

该问题提供了 iOS14 通过 NWBrowser 使用 Bonjour 的方式。虽然得到的是 NWEndpoint,但是可以通过 NWConnection来获取 ip 信息。


http://www.hkcw.cn/article/LycWvKaHUF.shtml

相关文章

day16 数组的常见操作和形状

目录 Numpy数组基础知识 数组的维度 数组的秩 数组的简单创建 zeros创建数组 ones创建数组 arange创建数组 数组的随机化创建 数组的遍历 数组的运算 数组的索引 一维数组索引 二维数组索引 三维数组索引 SHAP值的深入理解 知识点&#xff1a; numpy数组的创建&#xff1a;简单…

利用 Synonyms 中文近义词库调优 RAG 服务,基于 Ollama, DeepSeek R1, Langchain

目录 比对代码对比结果Synonyms 中文近义词 EmbeddingsHuggingFaceEmbeddings GitHub https://github.com/hailiang-wang/llm-get-started/tree/master/003_rag_langchain 本文介绍&#xff0c;在基于 RAG 服务实现问答的过程中&#xff0c;使用两种 Embeddings 模式下&#…

HTML 文件反编译指南:优化与学习网页代码

原文&#xff1a;HTML 文件反编译指南&#xff1a;优化与学习网页代码 | w3cschool笔记 (请勿将文章标记为付费&#xff01;&#xff01;&#xff01;&#xff09; 一、何为 HTML 文件反编译&#xff1f; 反编译 HTML 文件即将其从可读代码转换为更精简的形式。实际上&#…

在 ODROID-H3+ 上安装 Win11 系统

在 ODROID-H3 上安装 Windows 11 系统。 以下是完整的步骤&#xff0c;包括 BIOS 设置、U 盘制作、安装和驱动处理&#xff0c;全程不保留之前的系统数据。 ✅ 准备工作 1. 准备一个 ≥8GB 的 USB 启动盘 用另一台电脑制作 Windows 11 安装盘。 &#x1f449; 推荐工具&…

大话软工笔记—分离之业务与管理

1. 业务与管理的定义 业务&#xff0c;指企业为达成某个目标而进行的一系列活动&#xff08;业务指的是“做事”&#xff09;。 管理&#xff0c;为实现业务目标而进行的决策、计划、组织、指导、实施、控制的过程&#xff08;管理是“管事”&#xff0c;“事”指的是业务&am…

DeepSeek R1 模型小版本升级,DeepSeek-R1-0528都更新了哪些新特性?

DeepSeek-R1‑0528 技术剖析&#xff1a;思维链再进化&#xff0c;推理性能飙升 目录 版本概览深度思考能力再升级基准测试成绩功能与体验更新API 变动与示例模型开源与下载结语 版本概览 DeepSeek 团队今日发布 DeepSeek‑R1‑0528 —— 基于 DeepSeek V3 Base&#xff08;2…

请求分页中的内存分配

最小物理块数的确定 最小物理块数是确保进程能够正常运行所需的最少物理块数量。它是一个基础保障值&#xff0c;若分配的物理块数少于这个值&#xff0c;进程可能因无法完整加载必要页面而无法正常执行。例如&#xff0c;一个简单程序可能至少需要 3 个物理块来存放关键代码和…

痉挛性斜颈相关内容说明

一、颈部姿态的异常偏移​ 痉挛性斜颈会打破颈部原本自然笔直的状态&#xff0c;让颈部像被无形的力量牵引&#xff0c;出现不自主的歪斜、扭转。它就像打乱了颈部原本和谐的 “平衡游戏”&#xff0c;使得颈部姿态偏离正常&#xff0c;影响日常的体态与活动。​ 二、容易察觉…

【C++】位图

位图&#xff08;Bitmap&#xff09;是一种用于高效表示集合的数据结构&#xff0c;其核心思想是使用二进制位来指示某个元素是否存在。在位图中&#xff0c;每个元素对应一个二进制位&#xff0c;若该元素存在&#xff0c;则对应的位为1&#xff1b;若不存在&#xff0c;则为0…

初学c语言21(文件操作)

一.为什么使用文件 之前我们写的程序的数据都是存储到内存里面的&#xff0c;当程序结束时&#xff0c;内存回收&#xff0c;数据丢失&#xff0c; 再次运行程序时&#xff0c;就看不到上次程序的数据&#xff0c;如果要程序的数据一直保存得使用文件 二.文件 文件一般可以…

回车键为什么叫做“回车键”?

Enter键&#xff0c;也就是 “回车键”&#xff0c; 大家应该都不陌生。 可你知道它为什么叫“回车键”&#xff0c; 而不叫“输入键”、“登记键”嘛&#xff1f; 这要从机械英文打字机说起 因为电脑的普及&#xff0c;打字机几乎消失匿迹。 有的小伙伴们也许在小时候用过…

以太联Intellinet 分享:PoE 技术在医疗保健行业的创新应用

在当今科技飞速发展的时代&#xff0c;物联网(IoT)在医疗领域的应用正呈现出蓬勃兴起的态势。全球各地的医院以及老年生活中心纷纷引入物联网智能医疗解决方案&#xff0c;以实现设施运营的高效化与智能化。而在这背后&#xff0c;以太网供电(PoE)技术发挥着关键作用&#xff0…

大语言模型的技术原理与应用前景:从Transformer到ChatGPT

目录 摘要 1. 引言 2. Transformer架构核心原理 2.1 自注意力机制 2.2 位置编码 2.3 前馈神经网络 3. 从GPT到ChatGPT的演进 3.1 GPT系列模型架构 3.2 训练流程优化 4. 应用场景与案例分析 4.1 代码生成 4.2 文本摘要 4.3 问答系统 5. 挑战与未来方向 5.1 当前技…

CSS Day06

1.定位-相对和绝对和固定 (1)相对定位 position: relative; top: 100px; left: 200px; &#xff08;2&#xff09;绝对定位 就是子选择则器要用绝对定位&#xff0c;父选择器要用相对定位。 如果没有遵守此规则&#xff0c;那么小标签会跑到浏览器最角落&#xff1a; &#…

2025年5月24号高项综合知识真题以及答案解析(第1批次)

2025年5月24号高项综合知识真题以及答案解析

PowerDesigner通过SQL反向生成类图

PowerDesigner通过SQL反向生成类图 背景操作步骤步骤1: 选择这个步骤2: 目前我是选择的这个步骤3: 选择这个 其他 背景 工作学习 操作步骤 步骤1: 选择这个 步骤2: 目前我是选择的这个 步骤3: 选择这个 其他 其他同事告诉我的, 我还没有亲自尝试, 应该问题不大. 尝试后再反…

驱动灯珠芯片LT3743手册理解

1.引脚功能 1.EN/UVLO EN/UVLO引脚用作启用引脚&#xff0c;可在1.55V时开启内部电流偏置核心和子稳压器。该引脚没有上拉或下拉功能&#xff0c;因此正常工作需要电压偏置。当电压降至约0.5V时&#xff0c;系统将完全关闭。即EN/UVLO引脚的输入电压在1.55V至6V之间即可。 2.…

在 Mac 下 VSCode 中的终端使用 option + b 或 f 的快捷键变成输入特殊字符的解决方案

前言 在终端里&#xff0c;我们可以使用 option b 和 option f 来在我们输入的命令中进行快速的前后调整光标&#xff0c;但是&#xff0c;在未设置的情况下&#xff0c;在 MacOS 中&#xff0c;会变成输入特殊字符。 普通键盘上是 alt b 和 alt f &#xff0c;只是叫法不…

晨控CK-FR08与西门子PLC配置Profinet通讯连接操作手册

晨控CK-FR08与西门子PLC配置Profinet通讯连接操作手册 晨控CK-FR08系列作为晨控智能工业级别RFID读写器,支持大部分工业协议如RS232、RS485、以太网。支持工业协议Modbus RTU、Modbus TCP、Profinet、EtherNet/lP、EtherCat以及自由协议TCP/IP等。 本期主题&#xff1a;围绕CK…

【高能计算机】海思主板的特点和应用

在科技飞速发展的今天&#xff0c;主板作为电子设备的核心组件&#xff0c;其性能和功能直接影响着整个系统的运行效率和稳定性。继飞腾主板和龙芯主板的出现之后&#xff0c;高能计算机作为中国工控主板的研发生产商&#xff0c;紧跟时代发展的步伐&#xff0c;又推出一款海思…