iOS--NSNetService和NSNetServiceBrowser(Bonjour网络编程)
Cocoa 网络框架:
Cocoa 网络框架有三层,最底层的是基于 BSD socket库,然后是 Cocoa 中基于 C 的 CFNetwork,最上面一层是 Cocoa 中 Bonjour。通常我们无需与 socket 打交道,我们会使用经 Cocoa 封装的 CFNetwork 和 Bonjour 来完成大多数工作。注:cocoa 很多组件都有两种实现,一种是基于 C 的以 CF 开头的类(CF=Core Foundation),这是比较底层的;另一种是基于 Obj-C 的以 NS 开头的类(NS=Next Step),这种类抽象层次更高,易于使用。对于网络框架也一样。Bonjour 中 NSNetService 也有对应的 CFNetService,NSInputStream 有对应的 CFInputStream。
Bonjour 简介:
Bonjour(法语中的你好)是一种能够自动查询接入网络中的设备或应用程序的协议。Bonjour 抽象掉 ip 和 port 的概念,让我们聚焦于更容易为人类思维理解的 service。通过 Bonjour,一个应用程序 publish 一个网络服务 service,然后网络中的其他程序就能自动发现这个 service,从而可以向这个 service 查询其 ip 和 port,然后通过获得的 ip 和 port 建立 socket 链接进行通信。通常我们是通过 NSNetService 和 NSNetServiceBrowser 来使用 Bonjour 的,前者用于建立与发布 service,后者用于监听查询网络上的 service。
同步与异步操作:
大多数网络操作是阻塞模式的,比如链接的建立,等待接收数据,或发送数据给网络另一端。因此如果我们不进行异步处理的话,当在进行网络通信时,我们的 UI 机会被阻塞。有两种办法来处理阻塞问题:启用多个线程或更有效地利用当前线程。在这个例子中,我们使用后一种办法,我们通过 cocoa 提供的 run loop 来做这个事情,其工作原理是:将网络消息当作普通的事件丢到当前的 run loop 中,从而我们可以异步处理它们。
Run loops 简介:
run loop 是 thread 中的消息处理循环,有事件来则处理,无事件则啥也不做。cocoa 中的 run loop 可以处理用户 UI 消息,网络连接消息,timer 消息等。我们也可以添加其他的消息来源,如 socket 和 stream,从而让 run loop 也可以处理它们。
通过NSNetService发布socket
// 初始化服务,指定服务的域,类型,名称和端
NSNetService *service = [[NSNetService alloc] initWithDomain:@"local." type:@"_WE._tcp" name:@"WE_iPhone" port:];
service.delegate = self;
NSData *data = [NSNetService dataFromTXTRecordDictionary:@{@"node":@"http://www.we.com"}];
[service setTXTRecordData:data];
self.service = service;
// 发布
[service publish];
如果需要发布一个服务,需要在发布服务之前准备好服务并启动它。不过NSNetService的publish方法并不依赖它所发布的服务,不管服务是否准备好,是否启动,NSNetService的publish都可以成功将服务发布出去,只不过服务发布出去后其它使用这个服务的客户端会发现这个发布出来的服务是个无效服务。
发布服务成功之后,开始查找。
NSNetServiceDelegate代理
/*
* 即将发布
*/
- (void)netServiceWillPublish:(NSNetService *)sender {
NSLog(@"---------------netServiceWillPublish");
} /*
* 发布成功
*/
- (void)netServiceDidPublish:(NSNetService *)sender {
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
      dispatch_async(concurrentQueue, ^{
   NSRunLoop *mainRunLoop = [NSRunLoop currentRunLoop];
        NSNetServiceBrowser* browser = [[NSNetServiceBrowser alloc] init];
        browser.delegate = self;
        [browser scheduleInRunLoop:mainRunLoop forMode:NSRunLoopCommonModes];
        [browser searchForServicesOfType:@"_WE._tcp" inDomain:@"local."]; [mainRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:]]; });
} /*
* 发布失败,返回错误
*/
- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary<NSString *, NSNumber *> *)errorDict {
} /*
* 开始解析
*/
- (void)netServiceWillResolve:(NSNetService *)sender {
NSLog(@"--------------netServiceWillResolve");
} /*
* 解析成功
*/
- (void)netServiceDidResolveAddress:(NSNetService *)sender {
NSLog(@"netServiceDidResolveAddress---------=%@ =%@ =%@",service.name,service.addresses,service.hostName);
} /*
* 解析服务失败,解析出错
*/
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary<NSString *, NSNumber *> *)errorDict {
NSLog(@"------------netService didNotResolve =%@",errorDict);
} /*
* 停止服务
*/
- (void)netServiceDidStop:(NSNetService *)sender {
NSLog(@"--------------netServiceDidStop");
} /*
* 服务数据更新
*/
- (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)data {
NSLog(@"--------------netService didUpdateTXTRecordData");
} /*
* 连接成功输出流和输入流
*/
- (void)netService:(NSNetService *)sender didAcceptConnectionWithInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream {
NSLog(@"--------------netService didAcceptConnectionWithInputStream");
}
使用NSNetService框架中的NSNetServiceBrowser类去发现本地服务
接着使用NSNetServiceBrowser实例的searchForServicesOfType方法查找服务,方法中可以指定需要查找的服务类型和查找的域。以下样例查找“local.”域中的“_WE._tcp”服务
// 发现本地服务
NSNetServiceBrowser* browser = [[NSNetServiceBrowser alloc] init];
browser.delegate = self;
[browser scheduleInRunLoop:mainRunLoop forMode:NSRunLoopCommonModes];
[browser searchForServicesOfType:@"_WE._tcp" inDomain:@"local."];
[mainRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:]];
在“NSNetServiceBrowserDelegate”的以下方法中响应“didFindService”事件,就是找到服务的事件。其中的netService参数就是找到的服务,在netService参数中可以得到服务地址,服务主机名等信息
实现NSNetServiceBrowser实例的代理
/*
* 即将查找服务
*/
- (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");
} /*
* 发现客户端服务
*/
- (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:];
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");
}
在发现客户端里,设置NSNetService代理,在解析成功-(void)netServiceDidResolveAddress;方法里解析
可以拿到名称、类型、域、主机名、ip地址
/* Returns the name of the discovered or published service.
*/
@property (readonly, copy) NSString *name; /* Returns the type of the discovered or published service.
*/
@property (readonly, copy) NSString *type; /* Returns the domain of the discovered or published service.
*/
@property (readonly, copy) NSString *domain; /* Returns the DNS host name of the computer hosting the discovered or published service. If a successful resolve has not yet occurred, this method will return nil.
*/
@property (nullable, readonly, copy) NSString *hostName; /* The addresses of the service. This is an NSArray of NSData instances, each of which contains a single struct sockaddr suitable for use with connect(2). In the event that no addresses are resolved for the service or the service has not yet been resolved, an empty NSArray is returned.
*/
@property (nullable, readonly, copy) NSArray<NSData *> *addresses;
当解析成功客户端的IP、端口、类型、域之后,就可以通过建立连接进行通信。
iOS--NSNetService和NSNetServiceBrowser(Bonjour网络编程)的更多相关文章
- [Cocoa]深入浅出Cocoa之Bonjour网络编程
		
本文转载至 http://www.cnblogs.com/kesalin/archive/2011/09/15/cocoa_bonjour.html 深入浅出Cocoa之Bonjour网络编程 罗 ...
 - Objective-C ,ios,iphone开发基础:http网络编程
		
- (IBAction)loadData:(id)sender { NSURL* url = [NSURL URLWithString:@"http://162.105.65.251:808 ...
 - iOS网络编程模型
		
iOS网络编程层次结构也分为三层: Cocoa层:NSURL,Bonjour,Game Kit,WebKit Core Foundation层:基于 C 的 CFNetwork 和 CFNetServ ...
 - iOS 网络编程:socket
		
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
 - iOS网络编程笔记——Socket编程
		
一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是T ...
 - 【iOS】网络编程:上传图片到服务器
		
在网络编程中,如果需要上传图片,那么他的方法将会和普通的上传数据不同,下面将讲解如何上传图片. 环境信息: Mac OS X 10.9.5 Xcode 5.1.1 IOS 7.1 正文: - (NSU ...
 - iOS开发网络篇—网络编程基础
		
iOS开发网络篇—网络编程基础 一.为什么要学习网络编程 1.简单说明 在移动互联网时代,移动应用的特征有: (1)几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图 (2)只有通过 ...
 - iOS开发笔记4:HTTP网络通信及网络编程
		
这一篇主要总结iOS开发中进行HTTP通信及数据上传下载用到的方法.网络编程中常用的有第三方类库AFNetworking或者iOS7开始新推出的NSURLSession,还有NSURLSession的 ...
 - iOS开发之网络编程--5、NSURLSessionUploadTask+NSURLSessionDataDelegate代理上传
		
前言:关于NSURLSession的主要内容快到尾声了,这里就讲讲文件上传.关于文件上传当然就要使用NSURLSessionUploadTask,这里直接讲解常用的会和代理NSURLSessionDa ...
 
随机推荐
- HNU 13375 Flowery Trails (spfa最短路)
			
求最短路径覆盖的全部边权值和. 思路:分别从起点和终点两次求最短路,再比较两个点到起点的距离和他们之间的权值相加和是否等于最短路径. 这题很好 #include <cstring> #in ...
 - 使用C#模拟ASP.NET页面中按钮点击
			
c# 模拟Asp.net页面中的某个按钮的点击,向web服务器发出请求 主要就组织要提交的数据,然后以post方式提交. 假设我们有如下的网页 1 <% @ Page Language = &q ...
 - 解决SQL数据库无法脱机的问题
			
数据库无法脱机:原理——有人在占用. 解决办法: select * from master.sys.sysprocesses where dbid=db_id('数据库名称') kill [id]
 - Scala学习笔记(三)类层级和特质
			
无参方法 功能:将方法的定义转换为属性字段的定义: 作用范围:方法中没有参数,并且方法仅能通过读取所包含的对象属性去访问可变状态,而不改变可变状态,就可使用无参方法: 例子: abstract cla ...
 - 【原创】Mac上编译Hadoop1.0.3出现的一些问题
			
create-native-configure: [exec] configure.ac:47: error: possibly undefined macro: AC_PROG_LIBTOOL [e ...
 - POJ1276 - Cash Machine(多重背包)
			
题目大意 给定一个容量为M的背包以及n种物品,每种物品有一个体积和数量,要求你用这些物品尽量的装满背包 题解 就是多重背包~~~~用二进制优化了一下,就是把每种物品的数量cnt拆成由几个数组成,1,2 ...
 - HDU1671 - Phone List(Trie树)
			
题目大意 给定一些电话号码,判断是否有电话号码是其他电话号码的前缀 题解 裸Trie树嘛~~~~只需要一个插入过程即可,假设X是Y的前缀,在插入的过程中有两种情况,X在Y之前插入,那么在插入Y的时候经 ...
 - Codeforces Round #226 (Div. 2)B. Bear and Strings
			
/* 题意就是要找到包含“bear”的子串,计算出个数,需要注意的地方就是不要计算重复. */ 1 #include <stdio.h> #include <string.h> ...
 - POJ3254Corn Fields(状压DP)
			
题意: John 有一个豪华的M*N个格子组成的新牧场 他想种美味的玉米 但是有些位置不能种 而且他种地不选择相邻的格子 求所有可能的种地方法 (不种也算一种选择)输入:第一行M和N, 第二行M*N地 ...
 - NSNumber和Int之间的转换
			
int 转 NSNumber: [NSNumber numberWithInt:(int)]; NSNumber 转 int [(NSNumber) intValue]; 其他数据类型类似 有 ...