概念
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, 附加数据
内容。从而与手机建立连接,进行通信。