使用MDNS进行局域网服务发现(.NET Core)
使用MDNS进行局域网服务发现(.NET Core)
想要服务写的好,配置文件不可少。如果是一个复杂的系统,甚至配置文件都是需要进行动态调整的,做起来好像就不是那么方便了,通常情况下,asp.net core中的IConfiguration只能用来读取,没有提供保存功能,如果真的要操作一下,只能通过另外写方法来写入配置文件。可能是这个玩意设计就是Immutable的吧,总之,很难受。
前言
最近在做一个系统,局域网内工作基于C/S结构,一些配置项目需要从Server端发送到Client端。于是我想的第一件事情,就是给Client一个配置文件,通过Client中指定Server地址,发起通讯,并通过WebAPI,GRPC之类的东西获得数据。
貌似挺完美的,然而,这个系统的Client端是可以有很多个的,一个个配置那不是很麻烦,万一服务器地址改了...不敢想。有没有什么方法可以让Client自动发现Server,然后自动下载配置的?
方案
当然可以自己搭建一个UDP广播服务Server,然后Client端监听广播,收到广播之后即可知道IP地址信息,然后进行后续的数据传输操作。实现起来还是挺简单的,可以参考这个问答。
但是我太懒了,我找了找有规范协议的,大概有这么些:
1. WS-Discovery
WS-Discovery(Web Services Dynamic Discovery,WSD)是一种局域网内的服务发现多播协议,WS-Discovery定义了两种基本的实现服务发现机制的操作模式,即Ad-Hoc和Managed。
在Ad-Hoc模式下,客户端在一定的网络范围了以广播的形式发送探测(Probe)消息以搜寻目标服务。在该探测消息中,包含相应的搜寻条件。服务该条件的目标服务在接收到探测消息之后将自身相关的信息(包括地址)回复给作为广播消息发送源的客户端。客户端根据获取到的服务信息,选择适合的服务进行调用。
在Managed模式下,一个维护所有可用目标服务的中心发现代理(Discovery Proxy)被建立起来,客户端只需要将探测消息发送到该发现代理就可以得到相应的目标服务信息。由于在Ad-Hoc模式下的广播探测机制在Managed模式下被转变成单播形式,带来的好处就是极大地减轻了网络负载(Network Traffic)。
这个技术是OASIS标准协议,并且在WCF中有完整实现,对应可以搜索
UdpDiscoveryEndpoint就可以找到相关的信息。
最开始就是想使用这个协议的,不过WCF已经被弃用了,.NET Core没有对应的服务端支持,可惜。
2. Consul/ZooKeeper
既然WCF要被淘汰了,后续的替代,微软有一篇文章提到了这两个东西,基本上就是WS-Discovery的Managed方式,提供一个代理用于各种服务进行注册,但是还是需要提前配置这些服务注册服务器的地址,达不到我的要求。
3. MDNS
MDNS就是Multicast DNS,在内网没有DNS服务的时候,可以使用它来进行组播实现DNS。使用UDP协议的5353端口。基于这个协议比较著名的实现就是苹果的Bonjour,也有一个非常有名的zeroconf也是差不多这个意思,mDNS也是一个标准(RFC6762)。
在前面两个都用不了的情况下,只能用这个了。
实现
首先安装nuget包,这个包里面包含有server/Client端。
install-package Makaretu.Dns.Multicast
思路是这样的,基于ServiceDiscovery发布一个服务,并将额外的信息发布到然后监听各种mDNS请求,客户端通过服务名发送查询请求,并定位服务的地址信息,然后发送SRV,A和TXT查询请求获得服务全名,IP地址和额外配置信息。这样就获得了在局域网内的服务信息了。
客户端接收的时候,使用了服务名称作为筛选的依据。
服务发布端
var sd = new ServiceDiscovery();
//发布一个服务,服务名称是有讲究的,一般都是_
var p = new ServiceProfile("ipfs1", "_ipfs-discovery._udp", 5010);
p.AddProperty("connstr", "Server");
//必须要设置这一项,否则不解析TXT记录
sd.AnswersContainsAdditionalRecords = true;
sd.Advertise(p);
//sd.Announce(p);
Console.ReadKey();
sd.Unadvertise();
服务调用端
static void Main(string[] args)
{
var mdns = new MulticastService();
var sd = new ServiceDiscovery(mdns);
sd.ServiceInstanceDiscovered += (s, e) =>
{
if (e.Message.Answers.All(w => !w.Name.ToString().Contains("ipfs1"))) return;
Console.WriteLine($"service instance '{e.ServiceInstanceName}'");
// Ask for the service instance details.
mdns.SendQuery(e.ServiceInstanceName, type: DnsType.SRV);
};
mdns.AnswerReceived += (s, e) =>
{
if (e.Message.Answers.All(w => !w.Name.ToString().Contains("ipfs1"))) return;
// Is this an answer to a service instance details?
var servers = e.Message.Answers.OfType<SRVRecord>();
foreach (var server in servers)
{
Console.WriteLine($"host '{server.Target}' for '{server.Name}'");
// Ask for the host IP addresses.
mdns.SendQuery(server.Target, type: DnsType.A);
//mdns.SendQuery(server.Target, type: DnsType.AAAA);
}
// Is this an answer to host addresses?
var addresses = e.Message.Answers.OfType<AddressRecord>();
foreach (var address in addresses)
{
if (address.Address.AddressFamily== AddressFamily.InterNetwork)
Console.WriteLine($"host '{address.Name}' at {address.Address}");
}
// Get connectionstring from DNS TXT record.
var txts = e.Message.Answers.OfType<TXTRecord>();
foreach (var txt in txts)
{
//“connstr=Server”,获得对应connstr值
Console.WriteLine($"{txt.Strings.Single(w => w.Contains("connstr")).Split('=')[1]}");
//Console.WriteLine($"host '{address.Name}' at {address.Address}");
}
};
try
{
mdns.Start();
sd.QueryServiceInstances("_ipfs-discovery._udp");
Console.ReadKey();
}
finally
{
sd.Dispose();
mdns.Stop();
}
}
运行效果如下:

参考资料
- https://github.com/richardschneider/net-mdns
- http://www.360doc.com/content/13/0426/11/3735408_281032366.shtml
- https://www.cnblogs.com/azhqiang/p/11024705.html
使用MDNS进行局域网服务发现(.NET Core)的更多相关文章
- 发现AspNet.Core版本控制库Bug一枚,你还想入坑?
我,博客写作小白一枚,注册账号多年却未曾留下只言片语,在潜水的这些年里从大家的博客中收获了很多新的知识忽觉惶恐心有不安,是时候给大家分享一些我的经验和教训了.嗯嗯,实话告诉大家前面的话的都是来凑字数的 ...
- .NET Core微服务之基于Steeltoe使用Eureka实现服务注册与发现
Tip: 此篇已加入.NET Core微服务基础系列文章索引 => Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...
- ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core
背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...
- 详解Session分布式共享(.NET CORE版)
一.前言&回顾 在上篇文章Session分布式共享 = Session + Redis + Nginx中,好多同学留言问了我好多问题,其中印象深刻的有:nginx挂了怎么办?采用Redis的S ...
- EntityFramework Core 2.0执行原始查询如何防止SQL注入?
前言 接下来一段时间我们来讲讲EntityFramework Core基础,精简的内容,深入浅出,希望为想学习EntityFramework Core的童鞋提供一点帮助. EntityFramewor ...
- 开源纯C#工控网关+组态软件(十)移植到.NET Core
一. 引子 写这个开源系列已经十来篇了.自从十年前注册博客园以来,关注了张善友.老赵.xiaotie.深蓝色右手等一众大牛,也围观了逗比的吉日嘎啦.精密顽石等形形色色的园友.然而整整十年一篇文章都 ...
- [翻译 EF Core in Action 1.11] 何时不应该使用EF Core
Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...
- 你所不知道的ASP.NET Core MVC/WebApi基础系列(二)
前言 好久没冒泡了,算起来估计有快半年没更新博客了,估计是我第一次停更如此之久,人总有懒惰的时候,时间越长越懒惰,但是呢,不学又不行,持续的惰性是不行dei,要不然会被时光所抛弃,技术所淘汰,好吧,进 ...
- 搭建一个舒适的 .NET Core 开发环境
最近,一直在往.Net Core上迁移,随着工作的深入,发现.Net Core比.Net Framework好玩多了.不过目前还在windows下开发,虽然VisualStudio是宇宙第一神器,但是 ...
随机推荐
- C/C++编程日记:逻辑井字棋(圈叉)(用空格初始化)
问题描述: 3*3的棋盘中,只要一条线上出现三个一样的棋子就获胜(玩家或电脑):如果棋盘已经放满还未出现三个棋子一条线则打成平手. 具体细节: 初始化棋盘(用空格初始化) //初始化棋盘 vo ...
- Fastjson远程代码执行漏洞复现
fastjson漏洞简介 Fastjson是一个Java库,可用于将Java对象转换为其JSON表示形式.它还可以用于将JSON字符串转换为等效的Java对象,fastjson爆出多个反序列化远程命令 ...
- jsonp和普通的ajax区别
1.请求类型.返回类型不一样 2.返回数据类型
- FL Studio通道乐器设置页详讲
上一篇文章我们说到FL Studio通道乐器设置页每个标签页面中几乎都是由包络.低频振荡器和滤波器这三个部分组成.我们之前只对包络进行的简单的介绍,相信很多同学对它还有其他两个的功能的了解还是云里雾里 ...
- 借助Mac自带的强大的搜索功能,如何快速搜索打开Tuxera Disk Manager
现在很多小伙伴们在遇到Mac读写NTFS格式硬盘问题的时候,都会选择使用Tuxera NTFS这个磁盘读写工具.因为这款读写工具不仅可以帮助我们进行读写工作,还具有一个磁盘管理工具Disk Manag ...
- 使用QQ登陆
到这里https://connect.qq.com,申请成为开发者,然后等着审核通过 通过了,创建网站应用,回调地址必须是备案成功的网站上的,然后等着审核通过 通过了,得到正确的appid和appke ...
- python基础之条件语句
检查相等和不等 多个检查条件 age1 = 22 age2 = 19 s1 = age1 > 21 and age2 > 19 print(s1) s2 = age1 > 21 or ...
- sentinel--初级使用篇
1.官方资料 github官网地址:https://github.com/alibaba/Sentinel wiki:https://github.com/alibaba/Sentinel/wiki/ ...
- 小知识点 之 JVM -XX:MaxGCPauseMillis 与 -XX:GCTimeRatio
写在前边 JVM调优更多是针对不同应用类型及目标进行的调整,往往有很大的实验成份,通过实验来针对当前应用设置相对合适的参数,提高应用程序的性能与稳定性 最近在复习JVM,Parallel Scaven ...
- 【Java】Java socket通信使用read,readline函数的阻塞问题
Socket通信是Java网络编程中比较基础的部分,其原理其实就是源ip,源端口和目的ip,目的端口组成的套接字通信.其底层还设及到了TCP协议的通信. Java中的Socket通信可以通过客户端的S ...