.net framework4.8通过Makaretu.Dns.Multicast启用mDNS服务进行多播查询并且目标主机单播响应
Makaretu.Dns.Multicast版本0.27.0.0
想用winform做一个mDNS服务的组播功能,由于目标主机知道来源主机的ip地址,想着让目标主机直接点对点给源主机发送udp数据包
组播IP:224.0.0.251,端口:
5353,返回方式为QU(规定目标主机的返回方式为单播,QM:表示组播)。
1.首先nuget安装Makaretu.Dns.Multicast
2.直接上代码,因为我用的是QU查询,因此要调用SendUnicastQuery方法,如果是QM查询直接调用SendQuery
private void Form1_Load(object sender, EventArgs e) { //目标主机的响应很快,因此在发送组播之前要先监听本机的5353端口,一旦有目标主机往本机的5353端口发送数据可以马上处理 //先新建Udp监听本机5353端口 UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork); //SocketOptionLevel:指定要设置哪个级别的选项。在这里使用的是 SocketOptionLevel.Socket,表示要设置套接字级别的选项。 //SocketOptionName.ReuseAddress:允许同一个套接字地址在同一端口上立即重新使用,无需等待之前的连接关闭(理解为共享同一个5353端口,这样运行时才不会报错5353端口被占用) udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true);//设置 UDP 客户端的套接字选项 udpClient.Client.Bind(new IPEndPoint(IPAddress.Parse("本机以太网IP"), 5353)); // 设置监听本机5353端口 udpClient.BeginReceive(ReceiveCallback, udpClient); // 开始监听并接收Udp单播数据 //不用设置IP地址和5353端口,默认IP就是224.0.0.251,默认端口是:5353 MulticastService mdns = new MulticastService(); mdns.NetworkInterfaceDiscovered += (s, t) => mdns.SendUnicastQuery(new DomainName("DomainName查询.local"), DnsClass.IN, type: DnsType.ANY); mdns.AnswerReceived += OnGoodDnsMessage; mdns.QueryReceived += OnGoodDnsMessage; mdns.MalformedMessage += OnBadDnsMessage; mdns.Start(); } //接收并处理Udp单播数据包 private void ReceiveCallback(IAsyncResult ar) { UdpClient client = (UdpClient)ar.AsyncState; try { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); // 定义远程端点变量 byte[] receivedData = client.EndReceive(ar, ref remoteEP); txtLogs.AppendText($"--------------------------------------------------------------------\r\n"); txtLogs.AppendText($"IP:{remoteEP.Address},长度:{receivedData.Length}\r\n"); //Message可以把字符数组转成Dns报头,方便处理 Makaretu.Dns.Message message = new Makaretu.Dns.Message(); message.Read(receivedData, 0, receivedData.Length); if (message.AdditionalRecords.Count() > 0) { var test = message.AdditionalRecords; ResourceRecord rrObj = message.AdditionalRecords.FirstOrDefault(t => t.Type == DnsType.TXT); if (rrObj != null) { var txtRecord = (TXTRecord)rrObj; txtLogs.AppendText($"----------------解析---------------\r\n"); foreach (string rrStr in txtRecord.Strings) { txtLogs.AppendText($"{rrStr}\r\n"); } } } } catch(Exception ex) { txtLogs.AppendText(ex.ToString()); } // 继续监听数据包 client.BeginReceive(new AsyncCallback(ReceiveCallback), client); } private void OnBadDnsMessage(object sender, byte[] bytes) { } //接收多播数据并处理,目标主机发送多播情况下触发,因为本次主机是单播因此不会触发这个方法 private void OnGoodDnsMessage(object sender, MessageEventArgs e) { try { //查看应答信息 if(e.Message.AdditionalRecords.Count > 0) { foreach (ResourceRecord rr in e.Message.AdditionalRecords) { txtLogs.AppendText($"DomainName:{rr.Name},Canonical:{rr.CanonicalName},Type:{rr.Type.ToString()}\r\n"); string resultStr = rr.ToString(); byte[] byteArray = rr.GetData(); txtLogs.AppendText($":{resultStr},[DataLength]{byteArray.Length}\r\n"); } } if (e.Message.Answers.Count > 0) { txtLog2.AppendText($"\r\n***************Answers*****************\r\n"); foreach (ResourceRecord rr in e.Message.Answers) { txtLog2.AppendText($":{rr.ToString()}\r\n"); } } } catch(Exception ex) { txtLogs.AppendText(ex.ToString()); } }
----------------解析结果如下---------------
name=1.uos.test.tc
ver=设备软件版本号
ip=10.0.0.64
mac=32:44:83:d2:c3:b0
属性名=yes
app-online=yes//设备是否在线