From f4f1fdcd80ced54c80502e95ac3cb156751a502d Mon Sep 17 00:00:00 2001 From: kaka Date: Tue, 31 Jan 2023 12:48:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20HTTPing=20=E5=BB=B6?= =?UTF-8?q?=E8=BF=9F=E6=B5=8B=E9=80=9F=E6=A8=A1=E5=BC=8F(beta);=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20IP=20=E6=9C=BA=E5=9C=BA=E4=B8=89=E5=AD=97?= =?UTF-8?q?=E7=A0=81=20colo=20=E7=AD=9B=E9=80=89=E5=8A=9F=E8=83=BD(beta)?= =?UTF-8?q?=20(#282)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这两个功能目前仅为测试版,后续会大幅改动,以最终成品为准~ --- README.md | 16 ++++-- main.go | 17 +++++- task/download.go | 4 +- task/httping.go | 140 ++++++++++++++++++++++++++++++++++++++++++++++ task/tcping.go | 23 ++++++-- utils/csv.go | 14 +++++ utils/progress.go | 18 ++++-- 7 files changed, 213 insertions(+), 19 deletions(-) create mode 100644 task/httping.go diff --git a/README.md b/README.md index f6ede1b..c4102c2 100644 --- a/README.md +++ b/README.md @@ -122,11 +122,11 @@ https://github.com/XIU2/CloudflareSpeedTest 参数: -n 200 - 测速线程数量;越多测速越快,性能弱的设备 (如路由器) 请勿太高;(默认 200 最多 1000 ) + 测速线程数量;越多测速越快,性能弱的设备 (如路由器) 请勿太高;(默认 200 最多 1000) -t 4 - 延迟测速次数;单个 IP 延迟测速次数,为 1 时将过滤丢包的IP,TCP协议;(默认 4 次) + 延迟测速次数;单个 IP 延迟测速次数,为 1 时将过滤丢包的IP;(默认 4 次) -tp 443 - 指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口) + 指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口,httping模式下该参数无效) -dn 10 下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 10 个) @@ -154,8 +154,16 @@ https://github.com/XIU2/CloudflareSpeedTest -allip 测速全部的IP;对 IP 段中的每个 IP (仅支持 IPv4) 进行测速;(默认 每个 IP 段随机测速一个 IP) + -Httping + 启用HTTP ping;启用后会将tcping换成httping模式;(默认 不启用) + -HttpingColo DFW,LAX,SEA,SJC,FRA,MAD + 匹配机场三字码;需要匹配多个请使用英文逗号分割;(默认 匹配全部机场码,需要启用HTTP ping) + 目前已知区域:KIX,HKG,SIN,NRT,ICN,DFW,LAX,SEA,SJC,FRA,MAD + 目前已知大概率能扫描到美/法区域 + -HttpingTimeout 2000 + 指定httping超时时间;httping超时毫秒;(默认 2000 ms,需要启用HTTP ping) -v - 打印程序版本+检查版本更新 + 打印程序版本 + 检查版本更新 -h 打印帮助说明 ``` diff --git a/main.go b/main.go index 92ed636..c0a534d 100644 --- a/main.go +++ b/main.go @@ -28,9 +28,9 @@ https://github.com/XIU2/CloudflareSpeedTest -n 200 测速线程数量;越多测速越快,性能弱的设备 (如路由器) 请勿太高;(默认 200 最多 1000) -t 4 - 延迟测速次数;单个 IP 延迟测速次数,为 1 时将过滤丢包的IP,TCP协议;(默认 4 次) + 延迟测速次数;单个 IP 延迟测速次数,为 1 时将过滤丢包的IP;(默认 4 次) -tp 443 - 指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口) + 指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口,httping模式下该参数无效) -dn 10 下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 10 个) @@ -58,6 +58,14 @@ https://github.com/XIU2/CloudflareSpeedTest -allip 测速全部的IP;对 IP 段中的每个 IP (仅支持 IPv4) 进行测速;(默认 每个 IP 段随机测速一个 IP) + -Httping + 启用HTTP ping;启用后会将tcping换成httping模式;(默认 不启用) + -HttpingColo DFW,LAX,SEA,SJC,FRA,MAD + 匹配机场三字码;需要匹配多个请使用英文逗号分割;(默认 匹配全部机场码,需要启用HTTP ping) + 目前已知区域:KIX,HKG,SIN,NRT,ICN,DFW,LAX,SEA,SJC,FRA,MAD + 目前已知大概率能扫描到美/法区域 + -HttpingTimeout 2000 + 指定httping超时时间;httping超时毫秒;(默认 2000 ms,需要启用HTTP ping) -v 打印程序版本 + 检查版本更新 -h @@ -79,6 +87,9 @@ https://github.com/XIU2/CloudflareSpeedTest flag.BoolVar(&task.Disable, "dd", false, "禁用下载测速") flag.BoolVar(&task.TestAll, "allip", false, "测速全部 IP") flag.BoolVar(&printVersion, "v", false, "打印程序版本") + flag.BoolVar(&task.Httping, "Httping", false, "启用HTTP ping") + flag.StringVar(&task.HttpingColo, "HttpingColo", "", "匹配机场三字码") + flag.IntVar(&task.HttpingTimeout, "HttpingTimeout", 2000, "指定httping超时时间") flag.Usage = func() { fmt.Print(help) } flag.Parse() @@ -88,6 +99,8 @@ https://github.com/XIU2/CloudflareSpeedTest utils.InputMaxDelay = time.Duration(maxDelay) * time.Millisecond utils.InputMinDelay = time.Duration(minDelay) * time.Millisecond task.Timeout = time.Duration(downloadTime) * time.Second + task.HttpingColomap = task.MapColoMap() + task.HttpingRequest = task.GetRequest() if printVersion { println(version) diff --git a/task/download.go b/task/download.go index 3a80479..7cb4969 100644 --- a/task/download.go +++ b/task/download.go @@ -68,13 +68,13 @@ func TestDownloadSpeed(ipSet utils.PingDelaySet) (speedSet utils.DownloadSpeedSe } fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum) - bar := utils.NewBar(TestCount) + bar := utils.NewBar(TestCount, "", "") for i := 0; i < testNum; i++ { speed := downloadHandler(ipSet[i].IP) ipSet[i].DownloadSpeed = speed // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 if speed >= MinSpeed*1024*1024 { - bar.Grow(1) + bar.Grow(1, "") speedSet = append(speedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中 if len(speedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 break diff --git a/task/httping.go b/task/httping.go new file mode 100644 index 0000000..da18b6a --- /dev/null +++ b/task/httping.go @@ -0,0 +1,140 @@ +package task + +import ( + "crypto/tls" + "fmt" + "io" + "log" + "net" + "net/http" + "strings" + "sync" + "time" + + "CloudflareSpeedTest/utils" +) + +var ( + Httping bool //是否启用httping + HttpingTimeout int //设置超时时间,单位毫秒 + HttpingColo string //有值代表筛选机场三字码区域 +) + +var ( + HttpingColomap *sync.Map + HttpingRequest *http.Request +) + +// pingReceived pingTotalTime +func (p *Ping) httping(ip *net.IPAddr) (int, time.Duration) { + var fullAddress string + if isIPv4(ip.String()) { + fullAddress = fmt.Sprintf("%s", ip.String()) + } else { + fullAddress = fmt.Sprintf("[%s]", ip.String()) + } + hc := http.Client{ + Timeout: time.Duration(HttpingTimeout) * time.Millisecond, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } // #nosec + + traceURL := fmt.Sprintf("http://%s/cdn-cgi/trace", + fullAddress) + + // for connect and get colo + { + requ, err := http.NewRequest(http.MethodHead, traceURL, nil) + if err != nil { + return 0, 0 + } + requ.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36") + resp, err := hc.Do(requ) + if err != nil { + return 0, 0 + } + defer resp.Body.Close() + io.Copy(io.Discard, resp.Body) + + cfRay := resp.Header.Get("CF-RAY") + + colo := p.getColo(cfRay) + if colo == "" { + return 0, 0 + } + + } + + // for test delay + success := 0 + var delay time.Duration + for i := 0; i < PingTimes; i++ { + requ, err := http.NewRequest(http.MethodHead, traceURL, nil) + if err != nil { + log.Fatal("意外的错误,情报告:", err) + return 0, 0 + } + requ.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36") + if i == PingTimes-1 { + requ.Header.Set("Connection", "close") + } + startTime := time.Now() + resp, err := hc.Do(requ) + if err != nil { + continue + } + success++ + io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + duration := time.Since(startTime) + delay += duration + + } + + return success, delay + +} + +func MapColoMap() *sync.Map { + if HttpingColo == "" { + return nil + } + + colos := strings.Split(HttpingColo, ",") + colomap := &sync.Map{} + for _, colo := range colos { + colomap.Store(colo, colo) + } + return colomap +} + +func GetRequest() *http.Request { + req, err := http.NewRequest("GET", URL, nil) + if err != nil { + log.Fatal(err) + } + return req +} + +func (p *Ping) getColo(b string) string { + if b == "" { + return "" + } + idColo := strings.Split(b, "-") + + out := idColo[1] + + utils.ColoAble.Store(out, out) + + if HttpingColomap == nil { + return out + } + + _, ok := HttpingColomap.Load(out) + if ok { + return out + } + + return "" +} diff --git a/task/tcping.go b/task/tcping.go index 81d63cb..16e9f76 100644 --- a/task/tcping.go +++ b/task/tcping.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "sort" + "strconv" "sync" "time" @@ -54,7 +55,7 @@ func NewPing() *Ping { ips: ips, csv: make(utils.PingDelaySet, 0), control: make(chan bool, Routines), - bar: utils.NewBar(len(ips)), + bar: utils.NewBar(len(ips), "可用IP:", ""), } } @@ -62,7 +63,11 @@ func (p *Ping) Run() utils.PingDelaySet { if len(p.ips) == 0 { return p.csv } - fmt.Printf("开始延迟测速(模式:TCP,端口:%d,平均延迟上限:%v ms,平均延迟下限:%v ms)\n", TCPPort, utils.InputMaxDelay.Milliseconds(), utils.InputMinDelay.Milliseconds()) + if Httping { + fmt.Printf("开始延迟测速(模式:HTTP,端口:80,平均延迟上限:%v ms,平均延迟下限:%v ms)\n", utils.InputMaxDelay.Milliseconds(), utils.InputMinDelay.Milliseconds()) + } else { + fmt.Printf("开始延迟测速(模式:TCP,端口:%d,平均延迟上限:%v ms,平均延迟下限:%v ms)\n", TCPPort, utils.InputMaxDelay.Milliseconds(), utils.InputMinDelay.Milliseconds()) + } for _, ip := range p.ips { p.wg.Add(1) p.control <- false @@ -80,7 +85,7 @@ func (p *Ping) start(ip *net.IPAddr) { <-p.control } -//bool connectionSucceed float32 time +// bool connectionSucceed float32 time func (p *Ping) tcping(ip *net.IPAddr) (bool, time.Duration) { startTime := time.Now() var fullAddress string @@ -98,8 +103,12 @@ func (p *Ping) tcping(ip *net.IPAddr) (bool, time.Duration) { return true, duration } -//pingReceived pingTotalTime +// pingReceived pingTotalTime func (p *Ping) checkConnection(ip *net.IPAddr) (recv int, totalDelay time.Duration) { + if Httping { + recv, totalDelay = p.httping(ip) + return + } for i := 0; i < PingTimes; i++ { if ok, delay := p.tcping(ip); ok { recv++ @@ -120,7 +129,11 @@ func (p *Ping) appendIPData(data *utils.PingData) { // handle tcping func (p *Ping) tcpingHandler(ip *net.IPAddr) { recv, totalDlay := p.checkConnection(ip) - p.bar.Grow(1) + nowAble := len(p.csv) + if recv != 0 { + nowAble++ + } + p.bar.Grow(1, strconv.Itoa(nowAble)) if recv == 0 { return } diff --git a/utils/csv.go b/utils/csv.go index 0af80fd..d730dc2 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -6,7 +6,10 @@ import ( "log" "net" "os" + "sort" "strconv" + "strings" + "sync" "time" ) @@ -21,6 +24,7 @@ var ( InputMinDelay = minDelay Output = defaultOutput PrintNum = 10 + ColoAble sync.Map ) // 是否打印测试结果 @@ -139,6 +143,16 @@ func (s DownloadSpeedSet) Swap(i, j int) { } func (s DownloadSpeedSet) Print() { + var colos []string + ColoAble.Range(func(key, value interface{}) bool { + colos = append(colos, key.(string)) + return true + }) + if len(colos) != 0 { + sort.Strings(colos) + colostrings := strings.Join(colos, ",") + fmt.Println("\n下次可以考虑机场三字码参数:" + colostrings + "\n") + } if NoPrintResult() { return } diff --git a/utils/progress.go b/utils/progress.go index 85010c3..bc7ef66 100644 --- a/utils/progress.go +++ b/utils/progress.go @@ -1,19 +1,25 @@ package utils -import "github.com/cheggaaa/pb/v3" +import ( + "fmt" + + "github.com/cheggaaa/pb/v3" +) type Bar struct { pb *pb.ProgressBar } -func NewBar(count int) *Bar { - return &Bar{pb.Simple.Start(count)} +func NewBar(count int, MyStrStart, MyStrEnd string) *Bar { + tmpl := fmt.Sprintf(`{{counters . }}{{ bar . "[" "-" (cycle . "↖" "↗" "↘" "↙" ) "_" "]"}} %s {{string . "MyStr" | green}} %s `, MyStrStart, MyStrEnd) + bar := pb.ProgressBarTemplate(tmpl).Start(count) + return &Bar{pb: bar} } -func (b *Bar) Grow(num int) { - b.pb.Add(num) +func (b *Bar) Grow(num int, MyStrVal string) { + b.pb.Set("MyStr", MyStrVal).Add(num) } func (b *Bar) Done() { b.pb.Finish() -} \ No newline at end of file +}