Browse Source

新增 HTTPing 延迟测速模式(beta); 新增 IP 机场三字码 colo 筛选功能(beta) (#282)

这两个功能目前仅为测试版,后续会大幅改动,以最终成品为准~
kaka 2 years ago
parent
commit
f4f1fdcd80
7 changed files with 213 additions and 19 deletions
  1. 12 4
      README.md
  2. 15 2
      main.go
  3. 2 2
      task/download.go
  4. 140 0
      task/httping.go
  5. 18 5
      task/tcping.go
  6. 14 0
      utils/csv.go
  7. 12 6
      utils/progress.go

+ 12 - 4
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
         打印帮助说明
 ```

+ 15 - 2
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)

+ 2 - 2
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

+ 140 - 0
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 ""
+}

+ 18 - 5
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
 	}

+ 14 - 0
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
 	}

+ 12 - 6
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()
-}
+}