使用通道从一组DNS服务器中找到最快的响应者。

huangapple go评论73阅读模式
英文:

Using channels to find the fastest responder from a list of dns servers

问题

我正在尝试从一组服务器中找到对DNS请求响应最快的DNS服务器,使用通道进行操作。

这是我的代码。我想知道这样做是否正确,或者是否可以进行优化?

package main

import (
    "context"
    "fmt"
    "net"
    "time"
)

func main() {

    ch := make(chan string, 1)
    resolvers := []string{
        "1.1.1.1",
        "1.0.0.1",
        "8.8.4.4",
        "9.9.9.9",
        "8.8.8.8",
        "4.2.2.2",
    }

    for _, server := range resolvers {
        go func(server string, ch chan string) {
            // DNS客户端
            r := &net.Resolver{
                PreferGo: true,
                Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
                    d := net.Dialer{
                        Timeout: time.Millisecond * time.Duration(10000),
                    }
                    return d.DialContext(ctx, network, server+":53")
                },
            }
            _, _ = r.LookupHost(context.Background(), "www.google.com")
            ch <- server

        }(server, ch)
    }
    fmt.Printf("最快的服务器是 %s", <-ch)

}

希望对你有帮助!

英文:

I am trying to find the dns server that responds the fastest to a dns request, from a set of servers, using channels.

This is my code. I am wondering if this is the right way to do it or can it be optimized?

package main

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;net&quot;
    &quot;time&quot;
)

func main() {

    ch := make(chan string, 1)
    resolvers := []string{
        &quot;1.1.1.1&quot;,
        &quot;1.0.0.1&quot;,
        &quot;8.8.4.4&quot;,
        &quot;9.9.9.9&quot;,
        &quot;8.8.8.8&quot;,
        &quot;4.2.2.2&quot;,
    }

    for _, server := range resolvers {
        go func(server string, ch chan string) {
            // dns client
            r := &amp;net.Resolver{
                PreferGo: true,
                Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
                    d := net.Dialer{
                        Timeout: time.Millisecond * time.Duration(10000),
                    }
                    return d.DialContext(ctx, network, server+&quot;:53&quot;)
                },
            }
            _, _ = r.LookupHost(context.Background(), &quot;www.google.com&quot;)
            ch &lt;- server

        }(server, ch)
    }
    fmt.Printf(&quot;fastest is %s&quot;, &lt;-ch)

}


</details>


# 答案1
**得分**: 2

你可以按照以下方式计时请求并打印出准确的时间。

```go
package main

import (
	"context"
	"fmt"
	"net"
	"time"
)

type benchmark struct {
	server   string
	duration time.Duration
}

func main() {
	ch := make(chan benchmark, 1)
	resolvers := []string{
		"1.1.1.1",
		"1.0.0.1",
		"8.8.4.4",
		"9.9.9.9",
		"8.8.8.8",
		"4.2.2.2",
	}

	for _, server := range resolvers {
		go func(server string, ch chan<- benchmark) {
			// dns client
			r := &net.Resolver{
				PreferGo: true,
				Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
					d := net.Dialer{
						Timeout: time.Millisecond * time.Duration(10000),
					}
					return d.DialContext(ctx, network, server+":53")
				},
			}
			t1 := time.Now()
			defer func() {
				ch <- benchmark{server: server, duration: time.Since(t1)}
			}()
			_, _ = r.LookupHost(context.Background(), "www.google.com")
		}(server, ch)
	}
	for _, _ = range resolvers {
		b := <-ch
		fmt.Printf("服务器 %s 耗时 %s\n", b.server, b.duration)
	}
}

defer 函数将在 Lookup 函数返回后立即执行。有关 defer 的更多信息,你可能会喜欢我的博客文章。https://marcofranssen.nl/the-use-of-defer-in-go

在我的系统上,这显示的时间如下。

$ go run main.go
服务器 9.9.9.9 耗时 49.836914ms
服务器 8.8.4.4 耗时 49.954711ms
服务器 4.2.2.2 耗时 49.996936ms
服务器 1.1.1.1 耗时 49.933049ms
服务器 8.8.8.8 耗时 49.94578ms
服务器 1.0.0.1 耗时 49.997141ms

你可以将结果放入一个新的 benchmark 切片中,甚至可以根据持续时间对其进行排序。

另一个改进是多次运行此基准测试,然后对每个服务器取平均值或中位数,以获得更准确的结果。

英文:

You could time the requests as following and print the exact timings.

package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;net&quot;
	&quot;time&quot;
)

type benchmark struct {
	server   string
	duration time.Duration
}

func main() {
	ch := make(chan benchmark, 1)
	resolvers := []string{
		&quot;1.1.1.1&quot;,
		&quot;1.0.0.1&quot;,
		&quot;8.8.4.4&quot;,
		&quot;9.9.9.9&quot;,
		&quot;8.8.8.8&quot;,
		&quot;4.2.2.2&quot;,
	}

	for _, server := range resolvers {
		go func(server string, ch chan&lt;- benchmark) {
			// dns client
			r := &amp;net.Resolver{
				PreferGo: true,
				Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
					d := net.Dialer{
						Timeout: time.Millisecond * time.Duration(10000),
					}
					return d.DialContext(ctx, network, server+&quot;:53&quot;)
				},
			}
			t1 := time.Now()
			defer func() {
				ch &lt;- benchmark{server: server, duration: time.Since(t1)}
			}()
			_, _ = r.LookupHost(context.Background(), &quot;www.google.com&quot;)
		}(server, ch)
	}
	for _, _ = range resolvers {
		b := &lt;-ch
		fmt.Printf(&quot;server %s took %s\n&quot;, b.server, b.duration)
	}
}

The defer function will execute right after the Lookup function returns. For more info on defer you might like my blog. https://marcofranssen.nl/the-use-of-defer-in-go

This shows on my system timings as following.

$ go run main.go
server 9.9.9.9 took 49.836914ms
server 8.8.4.4 took 49.954711ms
server 4.2.2.2 took 49.996936ms
server 1.1.1.1 took 49.933049ms
server 8.8.8.8 took 49.94578ms
server 1.0.0.1 took 49.997141ms

You could e.g. put the results into a new benchmark slice which you could even sort based on the duration.

Another improvement to make is to run this benchmark multiple times and then take the average pr median for each server to get more accurate results over time.

huangapple
  • 本文由 发表于 2021年12月23日 17:35:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/70460145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定