使用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();
}
}

运行效果如下:

参考资料

使用MDNS进行局域网服务发现(.NET Core)的更多相关文章

  1. 发现AspNet.Core版本控制库Bug一枚,你还想入坑?

    我,博客写作小白一枚,注册账号多年却未曾留下只言片语,在潜水的这些年里从大家的博客中收获了很多新的知识忽觉惶恐心有不安,是时候给大家分享一些我的经验和教训了.嗯嗯,实话告诉大家前面的话的都是来凑字数的 ...

  2. .NET Core微服务之基于Steeltoe使用Eureka实现服务注册与发现

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  3. ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

    背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...

  4. 详解Session分布式共享(.NET CORE版)

    一.前言&回顾 在上篇文章Session分布式共享 = Session + Redis + Nginx中,好多同学留言问了我好多问题,其中印象深刻的有:nginx挂了怎么办?采用Redis的S ...

  5. EntityFramework Core 2.0执行原始查询如何防止SQL注入?

    前言 接下来一段时间我们来讲讲EntityFramework Core基础,精简的内容,深入浅出,希望为想学习EntityFramework Core的童鞋提供一点帮助. EntityFramewor ...

  6. 开源纯C#工控网关+组态软件(十)移植到.NET Core

    一.   引子 写这个开源系列已经十来篇了.自从十年前注册博客园以来,关注了张善友.老赵.xiaotie.深蓝色右手等一众大牛,也围观了逗比的吉日嘎啦.精密顽石等形形色色的园友.然而整整十年一篇文章都 ...

  7. [翻译 EF Core in Action 1.11] 何时不应该使用EF Core

    Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...

  8. 你所不知道的ASP.NET Core MVC/WebApi基础系列(二)

    前言 好久没冒泡了,算起来估计有快半年没更新博客了,估计是我第一次停更如此之久,人总有懒惰的时候,时间越长越懒惰,但是呢,不学又不行,持续的惰性是不行dei,要不然会被时光所抛弃,技术所淘汰,好吧,进 ...

  9. 搭建一个舒适的 .NET Core 开发环境

    最近,一直在往.Net Core上迁移,随着工作的深入,发现.Net Core比.Net Framework好玩多了.不过目前还在windows下开发,虽然VisualStudio是宇宙第一神器,但是 ...

随机推荐

  1. OAuth 2.0授权框架详解

    目录 简介 OAuth的构成 refresh Token Authorization Code模式 隐式授权 Resource Owner 授权密码认证 Client 认证授权 github的OAut ...

  2. HTML常用标签总结 [建议收藏]

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star 1. 标题标签 <h1> </h1> ...

  3. Python变量引用

    >>>a=3 >>>b=a >>>a=4 >>>b >>>3 >>>List1=[1,2,3 ...

  4. P5665 划分

    Part 1 先来看一个错误的贪心做法:假设当前结尾的一段和为 \(a\),等待加入结尾的一段和为 \(b\),现在要处理新进来的数 \(c\). \(a\leq b\),将 \(a\) 算入答案,将 ...

  5. JDBC【2】-- JDBC工作原理以及简单封装

    目录 1. 工作原理 1.1 加载驱动 1.1.1 类加载相关知识 1.1.2 为什么JDK 1.6之后不需要显示加载了? 1.2 驱动加载完成了,然后呢? 2. 简单封装 1. 工作原理 一般我们主 ...

  6. LaTeX中的表格

    表格插入代码及注释: 显示效果: 更多命令可以看相关文档,通过在命令行终端输入 texdoc booktab 等命令打开文档.

  7. Steps 组件的设计与实现

    NutUI 组件源码揭秘 前言 本文的主题是 Steps 组件的设计与实现.Steps 组件是 Steps 步骤和 Timeline 组件结合的组件,在此之前他们是两个不同的组件,在 NutUI 最近 ...

  8. C++-codeblocks安装

    2020-02-15 "Test_leetcode - Debug": The compiler's setup (GNU GCC Compiler) is invalid, so ...

  9. Bootstrap Blazor 组件介绍 Table (三)列数据格式功能介绍

    Bootstrap Blazor 是一套企业级 UI 组件库,适配移动端支持各种主流浏览器,已经在多个交付项目中使用.通过本套组件可以大大缩短开发周期,节约开发成本.目前已经开发.封装了 70 多个组 ...

  10. 音视频入门-18-手动生成一张GIF图片

    * 音视频入门文章目录 * GIF 编码知识 GIF 包含的数据块: 文件头(Header) 逻辑屏幕标识符(Logical Screen Descriptor) 全局颜色表(Global Color ...