原创文章,转载请注明出处
https://qiedd.com/

大家都是 HTTPS 了, 就用 DialTLSContext 吧

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"sort"
	"time"
)

func main() {
	api, _ := net.LookupIP("api.bilibili.com")

	results := map[string]*Result{}

	ch := make(chan struct {
		addr  *net.IP
		relay time.Duration
	})

	for _, ip := range api {
		go func(ip net.IP) {
			// 传入的 IP
			var addr string

			if ip.To4() == nil {
				addr = fmt.Sprintf("[%v]:443", ip.String())
			} else {
				addr = ip.String() + ":443"
			}

			// HTTP 客户端
			client := &http.Client{
				//Transport: &http2.Transport{
				//	DialTLSContext: func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error) {
				//		dialer := &net.Dialer{
				//			Timeout:   30 * time.Second,
				//			KeepAlive: 30 * time.Second,
				//		}
				//
				//		return tls.DialWithDialer(dialer, network, addr, cfg)
				//	},
				//	TLSClientConfig:    tlsConfig(),
				//	DisableCompression: true,
				//},
				Transport: &http.Transport{
					DialTLSContext: func(ctx context.Context, network, address string) (net.Conn, error) {

						dialConn, err := net.Dial(network, addr)
						if err != nil {
							return nil, err
						}

						config := &tls.Config{ServerName: "api.bilibili.com"}
						tlsConn := tls.Client(dialConn, config)

						if err = tlsConn.Handshake(); err != nil {
							return nil, err
						}

						return tlsConn, nil
					},
				},
			}

			// 计时器
			ticker := time.NewTicker(time.Second)

			for range ticker.C {
				now := time.Now()

				req, err := http.NewRequest("GET", "https://api.bilibili.com/x/report/click/now", nil)

				if err != nil {
					panic(err)
				}

				resp, err := client.Do(req)
				if err != nil {
					panic(err)
				}

				_, _ = io.ReadAll(resp.Body)

				ch <- struct {
					addr  *net.IP
					relay time.Duration
				}{addr: &ip, relay: time.Since(now)}
			}
		}(ip)
	}

	go func() {
		for {
			select {
			case r := <-ch:
				result, ok := results[r.addr.String()]
				if ok {
					result.TotalRelay = append(result.TotalRelay, r.relay)

					if len(result.TotalRelay) > 180 {
						result.TotalRelay = result.TotalRelay[1:]
					}

					var totalRelay time.Duration

					for _, v := range result.TotalRelay {
						totalRelay += v
					}

					result.AverageRelay = totalRelay / time.Duration(len(result.TotalRelay))
					result.CurrentRelay = r.relay

				} else {
					results[r.addr.String()] = &Result{
						Addr:         r.addr,
						CurrentRelay: r.relay,
						AverageRelay: r.relay,
						TotalRelay:   []time.Duration{},
					}
				}
			}
		}
	}()

	ticker := time.NewTicker(time.Second)

	for range ticker.C {
		clear := exec.Command("clear")
		clear.Stdout = os.Stdout
		if err := clear.Run(); err != nil {
			log.Fatal(err)
		}

		var regularResults []*Result

		for _, v := range results {
			regularResults = append(regularResults, v)
		}

		sort.Slice(regularResults, func(i, j int) bool {
			return regularResults[i].AverageRelay < regularResults[j].AverageRelay
		})

		for _, v := range regularResults {
			fmt.Printf("Addr: %v\tAvg Relay:%v\tCurrent Relay: %v \n",
				v.Addr.String(), v.AverageRelay, v.CurrentRelay)

		}
	}
}

type Result struct {
	Addr         *net.IP
	CurrentRelay time.Duration
	AverageRelay time.Duration
	TotalRelay   []time.Duration
}
分类: Go

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据