【区块链编程01】如何搜索其他节点——多播协议mDNS及Go语言实现服务器和浏览器

不知道区块链是如何寻找同服务节点,连入门都不算。更何况之后的零知识证明、身份认证和工作量证明?

下面看看mDNS到底是什么?

在计算机网络中 , 多播DNS ( mDNS )协议将主机名解析为不包含本地名称服务器的小型网络中的IP地址。 它是一种零配置服务,使用与单播域名系统 (DNS)基本相同的编程接口,数据包格式和操作语义。 虽然Stuart Cheshire将mDNS设计为独立协议,但它可以与标准DNS服务器协同工作。

mDNS协议发布为 RFC 6762使用IP多播用户数据报协议 (UDP)数据包,由Apple Bonjour和开源Avahi软件包实现。 Android包含mDNS实现。 mDNS也已在Windows 10中实现,最初仅限于发现网络打印机[3] ,后来也能够解析主机名。

mDNS可以与DNS服务发现 (DNS-SD)结合使用, DNS服务发现是RFC 6763中单独指定的配套零配置技术。

网络中的mDNS是什么形状?

mDNS 协议规定了端口为 5353,而 DNS 的端口是 53。

mDNS 基于 UDP 协议。DNS 一般也是基于 UDP 协议的,但是也可以使用 TCP 协议。

如果理解了 DNS 协议,再去理解 mDNS 协议就很简单了,区别只是 mDNS 一般作用在一个局域网内的,有特定的 IP 地址,也就是 224.0.0.251,有特定的端口 5353,mDNS 的作用是实现局域网内的服务发现,查询,注册,DNS 作用是实现域名的解析,作用大概是一样的。

Go语言如何实现一个mDNS?

代码位置:https://github.com/grandcat/zeroconf

在ZeroConf库的ReadMe文件中,实现了一个简单的mDNS服务。

服务:


package main

import (
	"github.com/grandcat/zeroconf"
	"log"
	"time"
	"os/signal"
	"os"
	"syscall"
)

func main()  {
//"_workstation._tcp"定义了服务名称
//参数形式:
//func Register(instance, service, domain string, port int, text []string, ifaces []net.Interface)

	server, err := zeroconf.Register("GoZeroconf", "_workstation._tcp", "local.", 42424, []string{"txtv=0", "lo=1", "la=2"}, nil)
	if err != nil {
	    panic(err)
	}
	defer server.Shutdown()

	// Clean exit.
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	select {
	case <-sig:
	    // Exit by user
	case <-time.After(time.Second * 120):
	    // Exit by timeout
	}

	log.Println("Shutting down.")
}

浏览器:

package main

import (
	"context"
	"github.com/grandcat/zeroconf"
	"log"
	"time"
)

func main()  {
	for  {
		// Discover all services on the network (e.g. _workstation._tcp)
		resolver, err := zeroconf.NewResolver(nil)
		if err != nil {
			log.Fatalln("Failed to initialize resolver:", err.Error())
		}

		entries := make(chan *zeroconf.ServiceEntry)
		go func(results <-chan *zeroconf.ServiceEntry) {
			for entry := range results {
				log.Println(entry)
			}
			log.Println("No more entries.")
		}(entries)

		ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
		defer cancel()
		err = resolver.Browse(ctx, "_workstation._tcp", "local.", entries)
		if err != nil {
			log.Fatalln("Failed to browse:", err.Error())
		}

		<-ctx.Done()
	}
}

服务未开启时,运行浏览器输出:

2020/04/12 12:38:10 No more entries.

开启服务(单行输出):

2020/04/12 12:38:29 &{{GoZeroconf _workstation._tcp local. 
_workstation._tcp.local. GoZeroconf._workstation._tcp.local. 
_services._dns-sd._udp.local.} jiang-P95-HR.local. 42424 
[txtv=0 lo=1 la=2] 3200 [192.168.1.103] 
[fe80::2055:d255:6444:ea00]}

 

你可能感兴趣的:(Go)