Bonjour (苹果电脑公司的服务器搜索协议)

Bonjour (苹果电脑公司的服务器搜索协议),使用不需要导入任何框架
一.Bonjour介绍

1、简介
一般在进行Socket编程或者网络访问的时候,首先需要确认对方网络服务已经开启,且需要知道对方的域名或地址以及端口,然后才可以进行进一步操作。在互联网上好点,网络服务方一般常年开启,且一般IP地址是固定的,另由于DNS服务的存在,只要记住对方的域名便可以。但是在局域网,设备不一定连在上面,即使连上了,服务也不一定开了,每当设备连接到局域网的时候,IP地址一般都是动态分配的,所以情况变的复杂。
Bonjour的存在便是苹果为了解决局域网设备间连接麻烦的问题。
Bonjour是一种协议(苹果递交给IETF的开放协议),使得局域网中的计算机可以方便的发布服务,发现服务和连接服务,达到零配置(http://zeroconf.org)的目的。

2、零配置网络服务
Zeroconf Working Group指出要实现零配置网络服务的3个要求:

1)、IP地址
2)、名字 到 IP地址 的转换(即使没有DNS服务器的情况下)
3)、发现网络中的服务
第一个要求,相关系统和设备可以直接支持的,如动态IP地址分配。
第二个要求,则可以通过多播(UDP协议向局域网内一组机器发送数据)的方式发送类似DNS查询的请求,开启着的网络服务收到之后便作出回应,告知自己的名字。
第三个要求则通过DNS-SD来实现

3、Bonjour的特点 —— 使局域网自行配置
不需要管理
不需要DHCP服务器来分配地址
不需要DNS服务器来映射名字到地址
不需要目录服务器来查找服务

4、Bonjour的工作模式

1)、发布服务。
在同一局域网中,服务器方开启服务,通过Bonjour接口将这个服务发布;

2)、浏览服务。
服务搜索方在服务列表中可以看到发布服务的设备的名字;

3)、连接服务。
服务搜索方选择想要连接的设备,便可以进行连接了。

整个过程中,无需实现知道服务发布方的IP地址和端口号。
我们常用的软件如iTunes的共享,keynote的remote控制或者支持Bonjour协议的打印机都可以看到Bonjour的影子。

二.如何自动分配地址
1、Bonjour挑选一个随即的地址,检查是否被使用
如果没有被使用,就给你用
如果被使用了,再试
2、使用”.local.”作为一个虚拟的顶层域名
3、对服务的广告
应用程序提供一个服务名和端口
遵循和DNS同样的模型——“具体到一般”
服务名._服务类型._传输协议名.域名
1)、服务名:是一个人可以阅读的描述性的名字
最多63个UTF-8字符
所有字符都允许
2)、_服务类型:是一个在IANA注册过的协议名,也可以用一串自定义的字符串
最多14个字符
格式是[a-z0-9]([a-z0-9\-]*[a-z0-9])?
3)、_传输协议名:TCP或者UDP,不支持自己的协议


例如:
Canon MP780._ipp._tcp.local.
服务名称:Canon MP780
服务类型:_ipp(Internet Printing Protocol——网络打印协议)
协议:_tcp
域名 local.
MyService._test._tcp.local.
服务名: MyService
服务类型:_test(未注册过的协议名,自定义的字符串)
协议:_tcp
域名local.


三.Bonjour的实现及使用
从上面的描述可以看出,Bonjour的用途便是在局域网内发布服务和搜索服务。
下面从实现层面讲解Bonjour。

层次
名称
Foundation
NSNetService/NSNetServiceBroswer
CoreFoundation
CFNetService/CFNetServiceBroswer
Low-Level Socket Based API
dns_sd.h(The DNS Service Discovery API)


一般情况下我们使用Foundation这一层接口就可以了,也是最方便的。
当然服务方在发布服务之前你得先启好网络服务,比如listening socket创建好,且开始侦听某个端口。


1、发布服务 ( NSNetService )
NSNetService * _netService;
_netService = [[NSNetService alloc] initWithDomain:@"local" type:@"_Test._tcp" name:@"_Test" port:53794];
_netService.delegate = self;
[_netService publish];

域名和name可以为缺省,直接传入参数@””,
域名为空白:暗示为 “ .local.”
name为空白:使用设备的iTunes名称

//且需要在dealloc里去掉delegate,停止服务
- (void)dealloc
{
_netService1.delegate = nil;
[_netService1 stop];
[_netService1 release];
[super dealloc];
}

常用代理方法
- (void)netServiceWillPublish:(NSNetService *)sender;
//成功后调用, 发布几个服务,会被调用几次
- (void)netServiceDidPublish:(NSNetService *)sender{
NSLog(@"发布Bonjour服务成功:domain(域名) = %@,type = %@,name = %@,port(端口) = %i",[sender domain],[sender type],[sender name],(int)[sender port]);
}
//发布服务失败调用,errorDict类似一个NSError有2个值,一个是错误域名,另一个是错误号码
- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict;


2、浏览服务 ( NSNetServiceBrowser )
NSNetServiceBrowser * _netServiceBrowser;
_netServiceBrowser = [[NSNetServiceBrowser alloc] init];
_netServiceBrowser.delegate = self;
[_netServiceBrowser searchForServicesOfType:@"_Test._tcp" inDomain:@""];


常用代理方法
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)aNetServiceBrowser;
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser;
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict;

//开始搜索指定type和domain的service,也就是调用searchForServicesOfType: inDomain:系统会调用下面的代理方法。
//搜索到几个服务,调用几次,当所有服务搜索完,moreComing会为NO,否则为YES
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing

{

NSNetService * lastService = [_serviceArray lastObject];
//开始搜索不同type的service了
if (![[lastService type] isEqual:[aNetService type]]) {

[_serviceArray removeAllObjects];
}

[_serviceArray addObject:aNetService];

if (moreComing == NO) {//指定类型的服务全部搜索完成了
[self.tableView reloadData];
}
}

//当所有指定服务remove完成,moreComing会为NO,否则为YES
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing;


3、连接服务 ( NSNetServiceBrowser 找到的 NSNetService )
上面发现的NSNetService是不带IP地址和端口信息的,使用前必须解析他们的地址。
从服务列表中选择一个已经发现的服务,进行Resolve,便可以获取服务的详细信息了。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//连接选中服务
NSNetService * aNetService = [_serviceArray objectAtIndex:indexPath.row];
aNetService.delegate = self;
//连接发现的service,5秒后超时
[aNetService resolveWithTimeout:5.0];
}


常用代理方法
//Resolve成功后调用
-(void)netServiceDidResolveAddress:(NSNetService *)sender;

-(void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict;
- (void)netServiceDidResolveAddress:(NSNetService *)sender;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值