mDNS Protocol 在iOS上的应用

概念

mdns多播dns(Multicast Domain Name System)mDNS主要实现了在没有传统DNS服务器的情况下使局域网内的主机实现相互发现和通信。在局域网中,设备和设备之前相互通信是需要知道对方的ip地址的,大多数情况,设备的ip不是静态ip地址,而是通过dhcp协议动态分配的ip 地址,此时就可以使用mdns协议来发现设备,并解析出设备的ip地址,来进行通信。

原理

这个真没研究,看rfc文档吧,如果了解dns协议,看这个会轻松很多。https://www.rfc-editor.org/rfc/rfc6762.html

网上很多文章在介绍原理时有如下介绍:每个进入局域网的主机,如果开启了 mDNS 服务的话,都会向局域网内的所有主机组播一个消息,我是谁,和我的IP地址是多少。然后其他也有该服务的主机就会响应,也会告诉你,它是谁,它的 IP 地址是多少,可以简单通过这段话来理解。

示例代码

服务端的代码这里就不写了,下面提供一下iOS使用Objective-C,启动mdns并发现设备的代码

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
   
//创建一个browser实例,该对象的运行需要在runloop中,请注意 
    self.browser = [[NSNetServiceBrowser alloc] init];
    self.browser.delegate = self;

    //调用下面方法后,就开始查询网络内所有的设备
    //type参数要按照自己的需要进行填充,下面仅作示例,即服务端启动时是什么协议,这里就用什么协议
    //domain参数可以为空,默认按照local.处理
    [self.browser searchForServicesOfType:@"_http._tcp" inDomain:@""];
    
}

- (void)printAddress {
    if (self.service.addresses.firstObject == nil) {
        NSLog(@"zero address");
        return;
    }

    //这里在mdns将域名解析出ip地址后,address中是个sockaddr结构体,可以按照如下方式解析出具体ip和port
    struct sockaddr_in *addr = (struct sockaddr_in *)(self.service.addresses.firstObject.bytes);
    NSString *ip = [NSString stringWithUTF8String:inet_ntoa(addr->sin_addr)];
    NSInteger port = ntohs(addr->sin_port);
    
    NSLog(@"ip:%@, port:%d", ip, port);

}

- (void)printTxtRecord:(NSData *)data {
    //通过系统代理收到的设备文本记录为NSData对象,可以按照下面方式转出具体的数据
    NSDictionary *dict = [NSNetService dictionaryFromTXTRecordData:data];
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        NSLog(@"key:%@, value:%@", key, [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding]);
    }];

}

#pragma mark - NSNetServiceBrowserDelegate

//通过上面调用[self.browser searchForServicesOfType:@"_http._tcp" inDomain:@"local."]方法
//如果局域网内搜到设备,会通过该代理回调
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
    NSLog(@"%s, service:%@, moreComing:%d", __FUNCTION__, service, moreComing);
    
    if ([service.name isEqualToString:@"240A64C9DFE8"]) {
        
        NSLog(@"name:%@, type:%@, domain:%@, hostName:%@",
              service.name,
              service.type,
              service.domain,
              service.hostName);
        
        self.service = service;
        self.service.delegate = self;
        
        //下面两个操作可以并行,通过测试,通常文本记录能够快速返回,而ip解析是耗时的

        //开始监听文本记录
        [self.service startMonitoring];
        //开始进行ip解析
        [self.service resolveWithTimeout:5.f];
    }

}

//当设备从局域网内消失时会通过该方法回调
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didRemoveService:(NSNetService *)service moreComing:(BOOL)moreComing {
    NSLog(@"%s, service:%@, moreComing:%d", __FUNCTION__, service, moreComing);
}

#pragma mark - NSNetServiceDelegate

//调用resolveWithTimeout解析成功后,会通过该方法回调
- (void)netServiceDidResolveAddress:(NSNetService *)sender {
    NSLog(@"%s", __FUNCTION__);

    [self printAddress];
}

//调用startMonitoring后会通过该方法回调,如果数据发生更新,该方法也会进行回调
- (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)data {
    NSLog(@"%s", __FUNCTION__);
    
    [self printTxtRecord:data];
}

IOT应用

iot领域,智能家居设备作为局域网内的一个设备,需要被手机app发现并与设备进行通信。此时就可以使用mdns协议来实现。
设备端需要注册并发布mdns服务。通常需要提供主机名,协议类型和端口号。另外,mdns还可以提供一些文本记录,作为附加数据,供手机app端获取。
手机app根据协议类型启动一个mdns服务来查询局域网内的设备,并获取ip, port, 附加数据内容。从而与手机建立连接,进行通信。

你可能感兴趣的:(mDNS Protocol 在iOS上的应用)