From 6f74e60444c6743c08ceaf1c2a2d0a61a3906f1e Mon Sep 17 00:00:00 2001 From: mazhuang Date: Tue, 9 Nov 2021 17:52:08 +0800 Subject: [PATCH 01/22] rebuild main --- IPRangeLoader.go | 116 ++++++++++++++-------------- main.go | 196 ++++++++++++++++++++++++----------------------- 2 files changed, 158 insertions(+), 154 deletions(-) diff --git a/IPRangeLoader.go b/IPRangeLoader.go index 1d6899eb..2dc00aa7 100644 --- a/IPRangeLoader.go +++ b/IPRangeLoader.go @@ -35,8 +35,7 @@ func getCidrIPRange(cidr string) (uint8, uint8) { seg4MinIP, seg4MaxIP := getIPSeg4Range(ipSegs, maskLen) //ipPrefix := ipSegs[0] + "." + ipSegs[1] + "." + ipSegs[2] + "." - return seg4MinIP, - seg4MaxIP + return seg4MinIP, seg4MaxIP } // 获取 IP 最后一段的区间 @@ -59,6 +58,7 @@ func loadFirstIPOfRangeFromFile(ipFile string) []net.IPAddr { if err != nil { log.Fatal(err) } + defer file.Close() firstIPs := make([]net.IPAddr, 0) scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) @@ -83,8 +83,8 @@ func loadFirstIPOfRangeFromFile(ipFile string) []net.IPAddr { MaxIPNum := getCidrHostNum(Mask) // 根据子网掩码获取主机数量 for IPRange.Contains(firstIP) { if allip { // 如果是测速全部 IP - for i := int(minIP); i <= int(maxIP); i++ { // 遍历 IP 最后一段最小值到最大值 - firstIP[15] = uint8(i) + for i := minIP; i <= maxIP; i++ { // 遍历 IP 最后一段最小值到最大值 + firstIP[15] = i firstIPCopy := make([]byte, len(firstIP)) copy(firstIPCopy, firstIP) firstIPs = append(firstIPs, net.IPAddr{IP: firstIPCopy}) @@ -103,60 +103,60 @@ func loadFirstIPOfRangeFromFile(ipFile string) []net.IPAddr { } } } - } else { //IPv6 - var tempIP uint8 - for IPRange.Contains(firstIP) { - //fmt.Println(firstIP) - //fmt.Println(firstIP[0], firstIP[1], firstIP[2], firstIP[3], firstIP[4], firstIP[5], firstIP[6], firstIP[7], firstIP[8], firstIP[9], firstIP[10], firstIP[11], firstIP[12], firstIP[13], firstIP[14], firstIP[15]) - if !strings.Contains(IPString, "/128") { - firstIP[15] = randipEndWith(255) // 随机 IP 的最后一段 - firstIP[14] = randipEndWith(255) // 随机 IP 的最后一段 - } - firstIPCopy := make([]byte, len(firstIP)) - copy(firstIPCopy, firstIP) - firstIPs = append(firstIPs, net.IPAddr{IP: firstIPCopy}) - tempIP = firstIP[13] - firstIP[13] += randipEndWith(255) - if firstIP[13] < tempIP { - tempIP = firstIP[12] - firstIP[12] += randipEndWith(255) - if firstIP[12] < tempIP { - tempIP = firstIP[11] - firstIP[11] += randipEndWith(255) - if firstIP[11] < tempIP { - tempIP = firstIP[10] - firstIP[10] += randipEndWith(255) - if firstIP[10] < tempIP { - tempIP = firstIP[9] - firstIP[9] += randipEndWith(255) - if firstIP[9] < tempIP { - tempIP = firstIP[8] - firstIP[8] += randipEndWith(255) - if firstIP[8] < tempIP { - tempIP = firstIP[7] - firstIP[7] += randipEndWith(255) - if firstIP[7] < tempIP { - tempIP = firstIP[6] - firstIP[6] += randipEndWith(255) - if firstIP[6] < tempIP { - tempIP = firstIP[5] - firstIP[5] += randipEndWith(255) - if firstIP[5] < tempIP { - tempIP = firstIP[4] - firstIP[4] += randipEndWith(255) - if firstIP[4] < tempIP { - tempIP = firstIP[3] - firstIP[3] += randipEndWith(255) - if firstIP[3] < tempIP { - tempIP = firstIP[2] - firstIP[2] += randipEndWith(255) - if firstIP[2] < tempIP { - tempIP = firstIP[1] - firstIP[1] += randipEndWith(255) - if firstIP[1] < tempIP { - tempIP = firstIP[0] - firstIP[0] += randipEndWith(255) - } + } + //IPv6 + var tempIP uint8 + for IPRange.Contains(firstIP) { + //fmt.Println(firstIP) + //fmt.Println(firstIP[0], firstIP[1], firstIP[2], firstIP[3], firstIP[4], firstIP[5], firstIP[6], firstIP[7], firstIP[8], firstIP[9], firstIP[10], firstIP[11], firstIP[12], firstIP[13], firstIP[14], firstIP[15]) + if !strings.Contains(IPString, "/128") { + firstIP[15] = randipEndWith(255) // 随机 IP 的最后一段 + firstIP[14] = randipEndWith(255) // 随机 IP 的最后一段 + } + firstIPCopy := make([]byte, len(firstIP)) + copy(firstIPCopy, firstIP) + firstIPs = append(firstIPs, net.IPAddr{IP: firstIPCopy}) + tempIP = firstIP[13] + firstIP[13] += randipEndWith(255) + if firstIP[13] < tempIP { + tempIP = firstIP[12] + firstIP[12] += randipEndWith(255) + if firstIP[12] < tempIP { + tempIP = firstIP[11] + firstIP[11] += randipEndWith(255) + if firstIP[11] < tempIP { + tempIP = firstIP[10] + firstIP[10] += randipEndWith(255) + if firstIP[10] < tempIP { + tempIP = firstIP[9] + firstIP[9] += randipEndWith(255) + if firstIP[9] < tempIP { + tempIP = firstIP[8] + firstIP[8] += randipEndWith(255) + if firstIP[8] < tempIP { + tempIP = firstIP[7] + firstIP[7] += randipEndWith(255) + if firstIP[7] < tempIP { + tempIP = firstIP[6] + firstIP[6] += randipEndWith(255) + if firstIP[6] < tempIP { + tempIP = firstIP[5] + firstIP[5] += randipEndWith(255) + if firstIP[5] < tempIP { + tempIP = firstIP[4] + firstIP[4] += randipEndWith(255) + if firstIP[4] < tempIP { + tempIP = firstIP[3] + firstIP[3] += randipEndWith(255) + if firstIP[3] < tempIP { + tempIP = firstIP[2] + firstIP[2] += randipEndWith(255) + if firstIP[2] < tempIP { + tempIP = firstIP[1] + firstIP[1] += randipEndWith(255) + if firstIP[1] < tempIP { + tempIP = firstIP[0] + firstIP[0] += randipEndWith(255) } } } diff --git a/main.go b/main.go index 259dfdc2..eeb8abe7 100644 --- a/main.go +++ b/main.go @@ -8,17 +8,18 @@ import ( "os" "runtime" "sort" - "strconv" "sync" "time" "github.com/cheggaaa/pb/v3" ) -var version, ipFile, outputFile, versionNew string -var disableDownload, ipv6Mode, allip bool -var tcpPort, printResultNum, downloadSecond int -var timeLimit, timeLimitLow, speedLimit float64 +var ( + version, ipFile, outputFile, versionNew string + disableDownload, ipv6Mode, allip bool + tcpPort, printResultNum, downloadSecond int + timeLimit, timeLimitLow, speedLimit float64 +) func init() { var printVersion bool @@ -139,19 +140,21 @@ func main() { ips := loadFirstIPOfRangeFromFile(ipFile) // 读入IP pingCount := len(ips) * pingTime // 计算进度条总数(IP*测试次数) bar := pb.Simple.Start(pingCount) // 进度条总数 - var wg sync.WaitGroup - var mu sync.Mutex - var data = make([]CloudflareIPData, 0) - var data2 = make([]CloudflareIPData, 0) + var ( + wg sync.WaitGroup + mu sync.Mutex + data = make([]CloudflareIPData, 0) + data2 = make([]CloudflareIPData, 0) + ) downloadTestTime = time.Duration(downloadSecond) * time.Second // 开始延迟测速 - fmt.Println("# XIU2/CloudflareSpeedTest " + version + "\n") + fmt.Printf("# XIU2/CloudflareSpeedTest %s \n", version) + ipVersion := "IPv4" if ipv6Mode { // IPv6 模式判断 - fmt.Println("开始延迟测速(模式:TCP IPv6,端口:" + strconv.Itoa(tcpPort) + ",平均延迟上限:" + fmt.Sprintf("%.2f", timeLimit) + " ms" + ",平均延迟下限:" + fmt.Sprintf("%.2f", timeLimitLow) + " ms):") - } else { - fmt.Println("开始延迟测速(模式:TCP IPv4,端口:" + strconv.Itoa(tcpPort) + ",平均延迟上限:" + fmt.Sprintf("%.2f", timeLimit) + " ms" + ",平均延迟下限:" + fmt.Sprintf("%.2f", timeLimitLow) + " ms):") + ipVersion = "IPv6" } + fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%.2f ms,平均延迟下限:%.2f ms):\n", ipVersion, tcpPort, timeLimit, timeLimitLow) control := make(chan bool, pingRoutine) for _, ip := range ips { wg.Add(1) @@ -167,15 +170,13 @@ func main() { // 延迟测速完毕后,以 [平均延迟上限] + [平均延迟下限] 条件过滤结果 if timeLimit != 9999 || timeLimitLow != 0 { for i := 0; i < len(data); i++ { - if float64(data[i].pingTime) <= timeLimit { // 平均延迟上限 - if float64(data[i].pingTime) > timeLimitLow { // 平均延迟下限 - data2 = append(data2, data[i]) // 延迟满足条件时,添加到新数组中 - } else { - continue - } - } else { + if float64(data[i].pingTime) > timeLimit { // 平均延迟上限 break } + if float64(data[i].pingTime) <= timeLimitLow { // 平均延迟下限 + continue + } + data2 = append(data2, data[i]) // 延迟满足条件时,添加到新数组中 } data = data2 data2 = []CloudflareIPData{} @@ -183,34 +184,7 @@ func main() { // 开始下载测速 if !disableDownload { // 如果禁用下载测速就跳过 - if len(data) > 0 { // IP数组长度(IP数量) 大于 0 时才会继续下载测速 - if len(data) < downloadTestCount { // 如果IP数组长度(IP数量) 小于下载测速数量(-dn),则次数修正为IP数 - downloadTestCount = len(data) - } - var downloadTestCount2 int // 临时的下载测速次数,即实际的下载测速数量 - if speedLimit > 0 { - downloadTestCount2 = len(data) // 如果指定了 [下载速度下限] 条件,则临时变量改为总数量(即一直测速下去,直到凑够下载测速数量 -dn) - } else { - downloadTestCount2 = downloadTestCount // 如果没有指定 [下载速度下限] 条件,则临时变量为下载测速数量(-dn) - } - fmt.Println("开始下载测速(下载速度下限:" + fmt.Sprintf("%.2f", speedLimit) + " MB/s,下载测速数量:" + strconv.Itoa(downloadTestCount) + ",下载测速队列:" + strconv.Itoa(downloadTestCount2) + "):") - bar = pb.Simple.Start(downloadTestCount) - for i := 0; i < downloadTestCount2; i++ { - _, speed := DownloadSpeedHandler(data[i].ip) - data[i].downloadSpeed = speed - // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 - if float64(speed)/1024/1024 >= speedLimit { - data2 = append(data2, data[i]) // 高于下载速度下限时,添加到新数组中 - bar.Add(1) - if len(data2) == downloadTestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 - break - } - } - } - bar.Finish() - } else { - fmt.Println("\n[信息] 延迟测速结果 IP 数量为 0,跳过下载测速。") - } + testDownloadSpeed(data, data2, bar) } if len(data2) > 0 { // 如果该数组有内容,说明指定了 [下载测速下限] 条件,且最少有 1 个满足条件的 IP @@ -223,49 +197,77 @@ func main() { printResult(data) // 显示最快结果 } +func testDownloadSpeed(data, data2 []CloudflareIPData, bar *pb.ProgressBar) { + if len(data) <= 0 { // IP数组长度(IP数量) 大于 0 时才会继续下载测速 + fmt.Println("\n[信息] 延迟测速结果 IP 数量为 0,跳过下载测速。") + return + } + if len(data) < downloadTestCount { // 如果IP数组长度(IP数量) 小于下载测速数量(-dn),则次数修正为IP数 + downloadTestCount = len(data) + } + // 临时的下载测速次数,即实际的下载测速数量 + downloadTestCount2 := downloadTestCount + // 如果没有指定 [下载速度下限] 条件,则临时变量为下载测速数量(-dn) + if speedLimit > 0 { + // 如果指定了 [下载速度下限] 条件,则临时变量改为总数量(即一直测速下去,直到凑够下载测速数量 -dn) + downloadTestCount2 = len(data) + } + fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", speedLimit, downloadTestCount, downloadTestCount2) + bar = pb.Simple.Start(downloadTestCount) + for i := 0; i < downloadTestCount2; i++ { + _, speed := DownloadSpeedHandler(data[i].ip) + data[i].downloadSpeed = speed + // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 + if float64(speed) >= speedLimit*1024*1024 { + data2 = append(data2, data[i]) // 高于下载速度下限时,添加到新数组中 + bar.Add(1) + if len(data2) == downloadTestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 + break + } + } + } + bar.Finish() +} + // 显示最快结果 func printResult(data []CloudflareIPData) { sysType := runtime.GOOS - if printResultNum > 0 { // 如果禁止直接输出结果就跳过 - dateString := convertToString(data) // 转为多维数组 [][]String - if len(dateString) > 0 { // IP数组长度(IP数量) 大于 0 时继续 - if len(dateString) < printResultNum { // 如果IP数组长度(IP数量) 小于 打印次数,则次数改为IP数量 - printResultNum = len(dateString) - } - if ipv6Mode { // IPv6 太长了,所以需要调整一下间隔 - fmt.Printf("%-40s%-5s%-5s%-5s%-6s%-11s\n", "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)") - for i := 0; i < printResultNum; i++ { - fmt.Printf("%-42s%-8s%-8s%-8s%-10s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) - } - } else { - fmt.Printf("%-16s%-5s%-5s%-5s%-6s%-11s\n", "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)") - for i := 0; i < printResultNum; i++ { - fmt.Printf("%-18s%-8s%-8s%-8s%-10s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) - } - } - - if versionNew != "" { - fmt.Println("\n*** 发现新版本 [" + versionNew + "]!请前往 [https://github.com/XIU2/CloudflareSpeedTest] 更新! ***") - } - - if sysType == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) - if outputFile != "" { - fmt.Printf("\n完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n按下 回车键 或 Ctrl+C 退出。", outputFile) - } else { - fmt.Printf("\n按下 回车键 或 Ctrl+C 退出。") - } - var pause int - fmt.Scanln(&pause) - } else { // 其它系统直接退出 - if outputFile != "" { - fmt.Println("\n完整测速结果已写入 " + outputFile + " 文件,请使用记事本/表格软件查看。") - } - } - } else { - fmt.Println("\n[信息] 完整测速结果 IP 数量为 0,跳过输出结果。") + if printResultNum <= 0 { // 如果禁止直接输出结果就跳过 + fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", outputFile) + return + } + dateString := convertToString(data) // 转为多维数组 [][]String + if len(dateString) <= 0 { // IP数组长度(IP数量) 大于 0 时继续 + fmt.Println("\n[信息] 完整测速结果 IP 数量为 0,跳过输出结果。") + return + } + if len(dateString) < printResultNum { // 如果IP数组长度(IP数量) 小于 打印次数,则次数改为IP数量 + printResultNum = len(dateString) + } + resHeader := []interface{}{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"} + if ipv6Mode { // IPv6 太长了,所以需要调整一下间隔 + fmt.Printf("%-40s%-5s%-5s%-5s%-6s%-11s\n", resHeader...) + for i := 0; i < printResultNum; i++ { + fmt.Printf("%-42s%-8s%-8s%-8s%-10s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) } } else { - fmt.Println("\n完整测速结果已写入 " + outputFile + " 文件,请使用记事本/表格软件查看。") + fmt.Printf("%-16s%-5s%-5s%-5s%-6s%-11s\n", resHeader...) + for i := 0; i < printResultNum; i++ { + fmt.Printf("%-18s%-8s%-8s%-8s%-10s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) + } + } + + if versionNew != "" { + fmt.Printf("\n*** 发现新版本 [%s]!请前往 [https://github.com/XIU2/CloudflareSpeedTest] 更新! ***\n", versionNew) + } + + if outputFile != "" { + fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", outputFile) + } + if sysType == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) + fmt.Printf("按下 回车键 或 Ctrl+C 退出。\n") + var pause int + fmt.Scanln(&pause) } } @@ -274,15 +276,17 @@ func checkUpdate() { timeout := time.Duration(10 * time.Second) client := http.Client{Timeout: timeout} res, err := client.Get("https://api.xiuer.pw/ver/cloudflarespeedtest.txt") - if err == nil { - // 读取资源数据 body: []byte - body, err := ioutil.ReadAll(res.Body) - // 关闭资源流 - res.Body.Close() - if err == nil { - if string(body) != version { - versionNew = string(body) - } - } + if err != nil { + return + } + // 读取资源数据 body: []byte + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return + } + // 关闭资源流 + defer res.Body.Close() + if string(body) != version { + versionNew = string(body) } } From 83c63e975e2c8df0698430d4e3417d8903f30ea9 Mon Sep 17 00:00:00 2001 From: mazhuang Date: Tue, 9 Nov 2021 18:44:17 +0800 Subject: [PATCH 02/22] rebuild tcping --- tcping.go | 123 ++++++++++++++++++++++------------------------ tcping/tcping.go | 19 +++++++ util.go | 6 +-- utils/csv.go | 59 ++++++++++++++++++++++ utils/progress.go | 9 ++++ 5 files changed, 148 insertions(+), 68 deletions(-) create mode 100644 tcping/tcping.go create mode 100644 utils/csv.go create mode 100644 utils/progress.go diff --git a/tcping.go b/tcping.go index 9c38df8c..6ac296e5 100644 --- a/tcping.go +++ b/tcping.go @@ -2,10 +2,10 @@ package main import ( "context" + "fmt" "io" "net" "net/http" - "strconv" "sync" "time" @@ -13,30 +13,24 @@ import ( ) //bool connectionSucceed float32 time -func tcping(ip net.IPAddr, tcpPort int) (bool, float32) { +func tcping(ip net.IPAddr, tcpPort int) (bool, time.Duration) { startTime := time.Now() - var fullAddress string + fullAddress := fmt.Sprintf("%s:%d", ip.String(), tcpPort) //fmt.Println(ip.String()) if ipv6Mode { // IPv6 需要加上 [] - fullAddress = "[" + ip.String() + "]:" + strconv.Itoa(tcpPort) - } else { - fullAddress = ip.String() + ":" + strconv.Itoa(tcpPort) + fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), tcpPort) } conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout) if err != nil { return false, 0 - } else { - var endTime = time.Since(startTime) - var duration = float32(endTime.Microseconds()) / 1000.0 - _ = conn.Close() - return true, duration } + defer conn.Close() + duration := time.Since(startTime) + return true, duration } //pingReceived pingTotalTime -func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) { - pingRecv := 0 - var pingTime float32 = 0.0 +func checkConnection(ip net.IPAddr, tcpPort int) (pingRecv int, pingTime time.Duration) { for i := 1; i <= failTime; i++ { pingSucceed, pingTimeCurrent := tcping(ip, tcpPort) if pingSucceed { @@ -44,14 +38,14 @@ func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) { pingTime += pingTimeCurrent } } - return pingRecv, pingTime + return } //return Success packetRecv averagePingTime specificIPAddr -func tcpingHandler(ip net.IPAddr, tcpPort int, pingCount int, progressHandler func(e progressEvent)) (bool, int, float32, net.IPAddr) { +func tcpingHandler(ip net.IPAddr, tcpPort, pingCount int, progressHandler func(e progressEvent)) (bool, int, time.Duration, net.IPAddr) { ipCanConnect := false pingRecv := 0 - var pingTime float32 = 0.0 + var pingTime time.Duration for !ipCanConnect { pingRecvCurrent, pingTimeCurrent := checkConnection(ip, tcpPort) if pingRecvCurrent != 0 { @@ -66,21 +60,20 @@ func tcpingHandler(ip net.IPAddr, tcpPort int, pingCount int, progressHandler fu break } } - if ipCanConnect { - progressHandler(AvailableIPFound) - for i := failTime; i < pingCount; i++ { - pingSuccess, pingTimeCurrent := tcping(ip, tcpPort) - progressHandler(NormalPing) - if pingSuccess { - pingRecv++ - pingTime += pingTimeCurrent - } - } - return true, pingRecv, pingTime / float32(pingRecv), ip - } else { + if !ipCanConnect { progressHandler(NoAvailableIPFound) return false, 0, 0, net.IPAddr{} } + progressHandler(AvailableIPFound) + for i := failTime; i < pingCount; i++ { + pingSuccess, pingTimeCurrent := tcping(ip, tcpPort) + progressHandler(NormalPing) + if pingSuccess { + pingRecv++ + pingTime += pingTimeCurrent + } + } + return true, pingRecv, pingTime / time.Duration(pingRecv), ip } func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, tcpPort int, pingCount int, csv *[]CloudflareIPData, control chan bool, progressHandler func(e progressEvent)) { @@ -126,47 +119,47 @@ func DownloadSpeedHandler(ip net.IPAddr) (bool, float32) { response, err := client.Get(url) if err != nil { return false, 0 - } else { - defer func() { _ = response.Body.Close() }() - if response.StatusCode == 200 { - timeStart := time.Now() - timeEnd := timeStart.Add(downloadTestTime) + } + defer response.Body.Close() + if response.StatusCode != 200 { + return false, 0 + } + timeStart := time.Now() + timeEnd := timeStart.Add(downloadTestTime) - contentLength := response.ContentLength - buffer := make([]byte, downloadBufferSize) + contentLength := response.ContentLength + buffer := make([]byte, downloadBufferSize) - var contentRead int64 = 0 - var timeSlice = downloadTestTime / 100 - var timeCounter = 1 - var lastContentRead int64 = 0 + var ( + contentRead int64 = 0 + timeSlice = downloadTestTime / 100 + timeCounter = 1 + lastContentRead int64 = 0 + ) - var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) - e := ewma.NewMovingAverage() + var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) + e := ewma.NewMovingAverage() - for contentLength != contentRead { - var currentTime = time.Now() - if currentTime.After(nextTime) { - timeCounter += 1 - nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) - e.Add(float64(contentRead - lastContentRead)) - lastContentRead = contentRead - } - if currentTime.After(timeEnd) { - break - } - bufferRead, err := response.Body.Read(buffer) - contentRead += int64(bufferRead) - if err != nil { - if err != io.EOF { - break - } else { - e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice))) - } - } + for contentLength != contentRead { + var currentTime = time.Now() + if currentTime.After(nextTime) { + timeCounter++ + nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) + e.Add(float64(contentRead - lastContentRead)) + lastContentRead = contentRead + } + if currentTime.After(timeEnd) { + break + } + bufferRead, err := response.Body.Read(buffer) + contentRead += int64(bufferRead) + if err != nil { + if err != io.EOF { + break } - return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120) - } else { - return false, 0 + e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice))) } } + return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120) + } diff --git a/tcping/tcping.go b/tcping/tcping.go new file mode 100644 index 00000000..eb0e13bd --- /dev/null +++ b/tcping/tcping.go @@ -0,0 +1,19 @@ +package tcping + +import ( + "net" + "sync" + + "CloudflareSpeedTest/utils" +) + +type Tcp struct { + wg *sync.WaitGroup + mutex *sync.Mutex + ip net.IPAddr + tcpPort int + pingCount int + csv *[]utils.CloudflareIPData + control chan bool + progressHandler func(e utils.ProgressEvent) +} diff --git a/util.go b/util.go index fb20cd5e..e1117ab9 100644 --- a/util.go +++ b/util.go @@ -18,7 +18,7 @@ type CloudflareIPData struct { pingReceived int recvRate float32 downloadSpeed float32 - pingTime float32 + pingTime time.Duration } func (cf *CloudflareIPData) getRecvRate() float32 { @@ -32,7 +32,7 @@ func (cf *CloudflareIPData) getRecvRate() float32 { func ExportCsv(filePath string, data []CloudflareIPData) { fp, err := os.Create(filePath) if err != nil { - log.Fatalf("创建文件["+filePath+"]句柄失败,%v", err) + log.Fatalf("创建文件[%s]失败:%v", filePath, err) return } defer fp.Close() @@ -48,7 +48,7 @@ func (cf *CloudflareIPData) toString() []string { result[1] = strconv.Itoa(cf.pingCount) result[2] = strconv.Itoa(cf.pingReceived) result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) - result[4] = strconv.FormatFloat(float64(cf.pingTime), 'f', 2, 32) + result[4] = cf.pingTime.String() result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32) return result } diff --git a/utils/csv.go b/utils/csv.go new file mode 100644 index 00000000..8e586fd5 --- /dev/null +++ b/utils/csv.go @@ -0,0 +1,59 @@ +package utils + +import ( + "encoding/csv" + "log" + "net" + "os" + "strconv" + "time" +) + +type CloudflareIPData struct { + ip net.IPAddr + pingCount int + pingReceived int + recvRate float32 + downloadSpeed float32 + pingTime time.Duration +} + +func (cf *CloudflareIPData) getRecvRate() float32 { + if cf.recvRate == 0 { + pingLost := cf.pingCount - cf.pingReceived + cf.recvRate = float32(pingLost) / float32(cf.pingCount) + } + return cf.recvRate +} + +func ExportCsv(filePath string, data []CloudflareIPData) { + fp, err := os.Create(filePath) + if err != nil { + log.Fatalf("创建文件[%s]失败:%v", filePath, err) + return + } + defer fp.Close() + w := csv.NewWriter(fp) //创建一个新的写入文件流 + w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"}) + w.WriteAll(convertToString(data)) + w.Flush() +} + +func (cf *CloudflareIPData) toString() []string { + result := make([]string, 6) + result[0] = cf.ip.String() + result[1] = strconv.Itoa(cf.pingCount) + result[2] = strconv.Itoa(cf.pingReceived) + result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) + result[4] = cf.pingTime.String() + result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32) + return result +} + +func convertToString(data []CloudflareIPData) [][]string { + result := make([][]string, 0) + for _, v := range data { + result = append(result, v.toString()) + } + return result +} diff --git a/utils/progress.go b/utils/progress.go new file mode 100644 index 00000000..cdb65890 --- /dev/null +++ b/utils/progress.go @@ -0,0 +1,9 @@ +package utils + +type ProgressEvent int + +const ( + NoAvailableIPFound ProgressEvent = iota + AvailableIPFound + NormalPing +) From 71671ebe66c23455f18305bf3c31aa90ff63f463 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Tue, 9 Nov 2021 23:39:42 +0800 Subject: [PATCH 03/22] rebuild tcping --- .gitignore | 2 + main.go | 4 +- tcping.go | 4 +- tcping/ping.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++ tcping/tcping.go | 19 ------- utils/csv.go | 24 +++++---- utils/progress.go | 23 +++++++++ 7 files changed, 173 insertions(+), 32 deletions(-) create mode 100644 tcping/ping.go delete mode 100644 tcping/tcping.go diff --git a/.gitignore b/.gitignore index 859fd68e..7970fb16 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ dist Releases +*.exe +*.csv diff --git a/main.go b/main.go index eeb8abe7..9efad35f 100644 --- a/main.go +++ b/main.go @@ -158,7 +158,7 @@ func main() { control := make(chan bool, pingRoutine) for _, ip := range ips { wg.Add(1) - control <- false + // control <- false handleProgress := handleProgressGenerator(bar) // 多线程进度条 go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress) } @@ -253,7 +253,7 @@ func printResult(data []CloudflareIPData) { } else { fmt.Printf("%-16s%-5s%-5s%-5s%-6s%-11s\n", resHeader...) for i := 0; i < printResultNum; i++ { - fmt.Printf("%-18s%-8s%-8s%-8s%-10s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) + fmt.Printf("%-18s%-8s%-8s%-8s%-15s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) } } diff --git a/tcping.go b/tcping.go index 6ac296e5..02e55eec 100644 --- a/tcping.go +++ b/tcping.go @@ -66,6 +66,7 @@ func tcpingHandler(ip net.IPAddr, tcpPort, pingCount int, progressHandler func(e } progressHandler(AvailableIPFound) for i := failTime; i < pingCount; i++ { + fmt.Println("failTime", failTime) pingSuccess, pingTimeCurrent := tcping(ip, tcpPort) progressHandler(NormalPing) if pingSuccess { @@ -78,6 +79,7 @@ func tcpingHandler(ip net.IPAddr, tcpPort, pingCount int, progressHandler func(e func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, tcpPort int, pingCount int, csv *[]CloudflareIPData, control chan bool, progressHandler func(e progressEvent)) { defer wg.Done() + // fmt.Println(ip.String()) success, pingRecv, pingTimeAvg, currentIP := tcpingHandler(ip, tcpPort, pingCount, progressHandler) if success { mutex.Lock() @@ -89,7 +91,7 @@ func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, tcpPo *csv = append(*csv, cfdata) mutex.Unlock() } - <-control + // <-control } func GetDialContextByAddr(fakeSourceAddr string) func(ctx context.Context, network, address string) (net.Conn, error) { diff --git a/tcping/ping.go b/tcping/ping.go new file mode 100644 index 00000000..6f5e4ac6 --- /dev/null +++ b/tcping/ping.go @@ -0,0 +1,129 @@ +package tcp + +import ( + "fmt" + "net" + "sync" + "time" + + "CloudflareSpeedTest/utils" +) + +const tcpConnectTimeout = time.Second * 1 + +type Ping struct { + wg *sync.WaitGroup + m *sync.Mutex + ips []net.IPAddr + isIPv6 bool + tcpPort int + pingCount int + csv []utils.CloudflareIPData + control chan bool + progressHandler func(e utils.ProgressEvent) +} + +func NewPing(ips []net.IPAddr, port, pingTime int, ipv6 bool) *Ping { + return &Ping{ + wg: &sync.WaitGroup{}, + m: &sync.Mutex{}, + ips: ips, + isIPv6: ipv6, + tcpPort: port, + pingCount: pingTime, + csv: make([]utils.CloudflareIPData, 0), + control: make(chan bool), + } +} + +func (p *Ping) Run() { + for _, ip := range p.ips { + p.wg.Add(1) + p.control <- false + go p.start(ip) + } +} + +func (p *Ping) start(ip net.IPAddr) { + defer p.wg.Done() + if ok, data := p.tcpingHandler(ip, nil); ok { + p.appendIPData(data) + } + <-p.control +} + +func (p *Ping) appendIPData(data *utils.PingData) { + p.m.Lock() + defer p.m.Unlock() + p.csv = append(p.csv, utils.CloudflareIPData{ + PingData: data, + }) +} + +//bool connectionSucceed float32 time +func (p *Ping) tcping(ip net.IPAddr) (bool, time.Duration) { + startTime := time.Now() + fullAddress := fmt.Sprintf("%s:%d", ip.String(), p.tcpPort) + //fmt.Println(ip.String()) + if p.isIPv6 { // IPv6 需要加上 [] + fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), p.tcpPort) + } + conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout) + if err != nil { + return false, 0 + } + defer conn.Close() + duration := time.Since(startTime) + return true, duration +} + +//pingReceived pingTotalTime +func (p *Ping) checkConnection(ip net.IPAddr) (pingRecv int, pingTime time.Duration) { + for i := 0; i < p.pingCount; i++ { + if pingSucceed, pingTimeCurrent := p.tcping(ip); pingSucceed { + pingRecv++ + pingTime += pingTimeCurrent + } + } + return +} + +//return Success packetRecv averagePingTime specificIPAddr +func (p *Ping) tcpingHandler(ip net.IPAddr, progressHandler func(e utils.ProgressEvent)) (bool, *utils.PingData) { + ipCanConnect := false + pingRecv := 0 + var pingTime time.Duration + for !ipCanConnect { + pingRecvCurrent, pingTimeCurrent := p.checkConnection(ip) + if pingRecvCurrent != 0 { + ipCanConnect = true + pingRecv = pingRecvCurrent + pingTime = pingTimeCurrent + } else { + ip.IP[15]++ + if ip.IP[15] == 0 { + break + } + break + } + } + if !ipCanConnect { + progressHandler(utils.NoAvailableIPFound) + return false, nil + } + progressHandler(utils.AvailableIPFound) + for i := 0; i < p.pingCount; i++ { + pingSuccess, pingTimeCurrent := p.tcping(ip) + progressHandler(utils.NormalPing) + if pingSuccess { + pingRecv++ + pingTime += pingTimeCurrent + } + } + return true, &utils.PingData{ + IP: ip, + Count: p.pingCount, + Received: pingRecv, + Delay: pingTime / time.Duration(pingRecv), + } +} diff --git a/tcping/tcping.go b/tcping/tcping.go deleted file mode 100644 index eb0e13bd..00000000 --- a/tcping/tcping.go +++ /dev/null @@ -1,19 +0,0 @@ -package tcping - -import ( - "net" - "sync" - - "CloudflareSpeedTest/utils" -) - -type Tcp struct { - wg *sync.WaitGroup - mutex *sync.Mutex - ip net.IPAddr - tcpPort int - pingCount int - csv *[]utils.CloudflareIPData - control chan bool - progressHandler func(e utils.ProgressEvent) -} diff --git a/utils/csv.go b/utils/csv.go index 8e586fd5..242c9eaf 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -9,19 +9,23 @@ import ( "time" ) +type PingData struct { + IP net.IPAddr + Count int + Received int + Delay time.Duration +} + type CloudflareIPData struct { - ip net.IPAddr - pingCount int - pingReceived int + *PingData recvRate float32 downloadSpeed float32 - pingTime time.Duration } func (cf *CloudflareIPData) getRecvRate() float32 { if cf.recvRate == 0 { - pingLost := cf.pingCount - cf.pingReceived - cf.recvRate = float32(pingLost) / float32(cf.pingCount) + pingLost := cf.Count - cf.Received + cf.recvRate = float32(pingLost) / float32(cf.Count) } return cf.recvRate } @@ -41,11 +45,11 @@ func ExportCsv(filePath string, data []CloudflareIPData) { func (cf *CloudflareIPData) toString() []string { result := make([]string, 6) - result[0] = cf.ip.String() - result[1] = strconv.Itoa(cf.pingCount) - result[2] = strconv.Itoa(cf.pingReceived) + result[0] = cf.IP.String() + result[1] = strconv.Itoa(cf.Count) + result[2] = strconv.Itoa(cf.Received) result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) - result[4] = cf.pingTime.String() + result[4] = cf.Delay.String() result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32) return result } diff --git a/utils/progress.go b/utils/progress.go index cdb65890..cf14e271 100644 --- a/utils/progress.go +++ b/utils/progress.go @@ -1,5 +1,7 @@ package utils +import "github.com/cheggaaa/pb/v3" + type ProgressEvent int const ( @@ -7,3 +9,24 @@ const ( AvailableIPFound NormalPing ) + +type Bar struct { + *pb.ProgressBar +} + +func NewBar(count int) *Bar { + return &Bar{pb.Simple.Start(count)} +} + +func handleProgressGenerator(pb *pb.ProgressBar) func(e ProgressEvent) { + return func(e ProgressEvent) { + switch e { + case NoAvailableIPFound: + // pb.Add(pingTime) + case AvailableIPFound: + // pb.Add(failTime) + case NormalPing: + pb.Increment() + } + } +} From 4d64abb94d15a5a7d760babe8801c283c3805c84 Mon Sep 17 00:00:00 2001 From: mazhuang Date: Wed, 10 Nov 2021 12:25:10 +0800 Subject: [PATCH 04/22] tcping add progressbar --- main.go | 16 ++++-- task/ip.go | 6 +++ task/tcping.go | 135 ++++++++++++++++++++++++++++++++++++++++++++++ tcping.go | 2 +- tcping/ping.go | 129 -------------------------------------------- utils/csv.go | 87 +++++++++++++++++++++++++----- utils/progress.go | 10 +++- 7 files changed, 237 insertions(+), 148 deletions(-) create mode 100644 task/ip.go create mode 100644 task/tcping.go delete mode 100644 tcping/ping.go diff --git a/main.go b/main.go index 9efad35f..3b3a621b 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,8 @@ import ( "sync" "time" + "CloudflareSpeedTest/task" + "github.com/cheggaaa/pb/v3" ) @@ -76,12 +78,16 @@ https://github.com/XIU2/CloudflareSpeedTest flag.Float64Var(&speedLimit, "sl", 0, "下载速度下限") flag.IntVar(&printResultNum, "p", 20, "显示结果数量") flag.BoolVar(&disableDownload, "dd", false, "禁用下载测速") - flag.BoolVar(&ipv6Mode, "ipv6", false, "禁用下载测速") + flag.BoolVar(&ipv6Mode, "ipv6", false, "启用IPv6") flag.BoolVar(&allip, "allip", false, "测速全部 IP") flag.StringVar(&ipFile, "f", "ip.txt", "IP 数据文件") flag.StringVar(&outputFile, "o", "result.csv", "输出结果文件") flag.BoolVar(&printVersion, "v", false, "打印程序版本") + task.TCPPort = tcpPort + task.IPv6 = ipv6Mode + task.DefaultRoutine = pingRoutine + flag.Usage = func() { fmt.Print(help) } flag.Parse() if printVersion { @@ -155,16 +161,20 @@ func main() { ipVersion = "IPv6" } fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%.2f ms,平均延迟下限:%.2f ms):\n", ipVersion, tcpPort, timeLimit, timeLimitLow) + + // ping := task.NewPing(ips) + // ping.Run() control := make(chan bool, pingRoutine) for _, ip := range ips { wg.Add(1) - // control <- false + control <- false handleProgress := handleProgressGenerator(bar) // 多线程进度条 go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress) } wg.Wait() bar.Finish() - + // data := ping.Data() + // sort.Sort(utils.CloudflareIPDataSet(data)) sort.Sort(CloudflareIPDataSet(data)) // 排序(按延迟,从低到高,不同丢包率会分开单独按延迟和丢包率排序) // 延迟测速完毕后,以 [平均延迟上限] + [平均延迟下限] 条件过滤结果 diff --git a/task/ip.go b/task/ip.go new file mode 100644 index 00000000..5815c5a4 --- /dev/null +++ b/task/ip.go @@ -0,0 +1,6 @@ +package task + +var ( + // IPv6 IP version is 6 + IPv6 = false +) diff --git a/task/tcping.go b/task/tcping.go new file mode 100644 index 00000000..b065e9d9 --- /dev/null +++ b/task/tcping.go @@ -0,0 +1,135 @@ +package task + +import ( + "fmt" + "net" + "sync" + "time" + + "CloudflareSpeedTest/utils" +) + +const ( + tcpConnectTimeout = time.Second * 1 + maxRoutine = 1000 +) + +var ( + DefaultRoutine = 200 + TCPPort int = 443 + PingTimes int = 4 +) + +type Ping struct { + wg *sync.WaitGroup + m *sync.Mutex + ips []net.IPAddr + csv utils.PingDelaySet + control chan bool + bar *utils.Bar +} + +func NewPing(ips []net.IPAddr) *Ping { + return &Ping{ + wg: &sync.WaitGroup{}, + m: &sync.Mutex{}, + ips: ips, + csv: make(utils.PingDelaySet, 0), + control: make(chan bool, DefaultRoutine), + bar: utils.NewBar(len(ips) * PingTimes), + } +} + +func (p *Ping) Run() utils.PingDelaySet { + for _, ip := range p.ips { + p.wg.Add(1) + p.control <- false + go p.start(ip) + } + p.wg.Wait() + p.bar.Done() + return p.csv +} + +func (p *Ping) start(ip net.IPAddr) { + defer p.wg.Done() + p.tcpingHandler(ip) + <-p.control +} + +//bool connectionSucceed float32 time +func (p *Ping) tcping(ip net.IPAddr) (bool, time.Duration) { + startTime := time.Now() + fullAddress := fmt.Sprintf("%s:%d", ip.String(), TCPPort) + //fmt.Println(ip.String()) + if IPv6 { // IPv6 需要加上 [] + fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), TCPPort) + } + conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout) + if err != nil { + return false, 0 + } + defer conn.Close() + duration := time.Since(startTime) + return true, duration +} + +//pingReceived pingTotalTime +func (p *Ping) checkConnection(ip net.IPAddr) (recv int, totalDelay time.Duration) { + for i := 0; i < PingTimes; i++ { + if ok, delay := p.tcping(ip); ok { + recv++ + totalDelay += delay + } + } + return +} + +func (p *Ping) appendIPData(data *utils.PingData) { + p.m.Lock() + defer p.m.Unlock() + p.csv = append(p.csv, utils.CloudflareIPData{ + PingData: data, + }) +} + +//return Success packetRecv averagePingTime specificIPAddr +func (p *Ping) tcpingHandler(ip net.IPAddr) { + ipCanConnect := false + pingRecv := 0 + var delay time.Duration + for !ipCanConnect { + recv, totalDlay := p.checkConnection(ip) + if recv > 0 { + ipCanConnect = true + pingRecv = recv + delay = totalDlay + } else { + ip.IP[15]++ + if ip.IP[15] == 0 { + break + } + break + } + } + p.bar.Grow(PingTimes) + if !ipCanConnect { + return + } + // for i := 0; i < PingTimes; i++ { + // pingSuccess, pingTimeCurrent := p.tcping(ip) + // progressHandler(utils.NormalPing) + // if pingSuccess { + // pingRecv++ + // pingTime += pingTimeCurrent + // } + // } + data := &utils.PingData{ + IP: ip, + Sended: PingTimes, + Received: pingRecv, + Delay: delay / time.Duration(pingRecv), + } + p.appendIPData(data) + return +} diff --git a/tcping.go b/tcping.go index 02e55eec..1cbacd00 100644 --- a/tcping.go +++ b/tcping.go @@ -91,7 +91,7 @@ func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, tcpPo *csv = append(*csv, cfdata) mutex.Unlock() } - // <-control + <-control } func GetDialContextByAddr(fakeSourceAddr string) func(ctx context.Context, network, address string) (net.Conn, error) { diff --git a/tcping/ping.go b/tcping/ping.go deleted file mode 100644 index 6f5e4ac6..00000000 --- a/tcping/ping.go +++ /dev/null @@ -1,129 +0,0 @@ -package tcp - -import ( - "fmt" - "net" - "sync" - "time" - - "CloudflareSpeedTest/utils" -) - -const tcpConnectTimeout = time.Second * 1 - -type Ping struct { - wg *sync.WaitGroup - m *sync.Mutex - ips []net.IPAddr - isIPv6 bool - tcpPort int - pingCount int - csv []utils.CloudflareIPData - control chan bool - progressHandler func(e utils.ProgressEvent) -} - -func NewPing(ips []net.IPAddr, port, pingTime int, ipv6 bool) *Ping { - return &Ping{ - wg: &sync.WaitGroup{}, - m: &sync.Mutex{}, - ips: ips, - isIPv6: ipv6, - tcpPort: port, - pingCount: pingTime, - csv: make([]utils.CloudflareIPData, 0), - control: make(chan bool), - } -} - -func (p *Ping) Run() { - for _, ip := range p.ips { - p.wg.Add(1) - p.control <- false - go p.start(ip) - } -} - -func (p *Ping) start(ip net.IPAddr) { - defer p.wg.Done() - if ok, data := p.tcpingHandler(ip, nil); ok { - p.appendIPData(data) - } - <-p.control -} - -func (p *Ping) appendIPData(data *utils.PingData) { - p.m.Lock() - defer p.m.Unlock() - p.csv = append(p.csv, utils.CloudflareIPData{ - PingData: data, - }) -} - -//bool connectionSucceed float32 time -func (p *Ping) tcping(ip net.IPAddr) (bool, time.Duration) { - startTime := time.Now() - fullAddress := fmt.Sprintf("%s:%d", ip.String(), p.tcpPort) - //fmt.Println(ip.String()) - if p.isIPv6 { // IPv6 需要加上 [] - fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), p.tcpPort) - } - conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout) - if err != nil { - return false, 0 - } - defer conn.Close() - duration := time.Since(startTime) - return true, duration -} - -//pingReceived pingTotalTime -func (p *Ping) checkConnection(ip net.IPAddr) (pingRecv int, pingTime time.Duration) { - for i := 0; i < p.pingCount; i++ { - if pingSucceed, pingTimeCurrent := p.tcping(ip); pingSucceed { - pingRecv++ - pingTime += pingTimeCurrent - } - } - return -} - -//return Success packetRecv averagePingTime specificIPAddr -func (p *Ping) tcpingHandler(ip net.IPAddr, progressHandler func(e utils.ProgressEvent)) (bool, *utils.PingData) { - ipCanConnect := false - pingRecv := 0 - var pingTime time.Duration - for !ipCanConnect { - pingRecvCurrent, pingTimeCurrent := p.checkConnection(ip) - if pingRecvCurrent != 0 { - ipCanConnect = true - pingRecv = pingRecvCurrent - pingTime = pingTimeCurrent - } else { - ip.IP[15]++ - if ip.IP[15] == 0 { - break - } - break - } - } - if !ipCanConnect { - progressHandler(utils.NoAvailableIPFound) - return false, nil - } - progressHandler(utils.AvailableIPFound) - for i := 0; i < p.pingCount; i++ { - pingSuccess, pingTimeCurrent := p.tcping(ip) - progressHandler(utils.NormalPing) - if pingSuccess { - pingRecv++ - pingTime += pingTimeCurrent - } - } - return true, &utils.PingData{ - IP: ip, - Count: p.pingCount, - Received: pingRecv, - Delay: pingTime / time.Duration(pingRecv), - } -} diff --git a/utils/csv.go b/utils/csv.go index 242c9eaf..f93452d5 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -5,13 +5,22 @@ import ( "log" "net" "os" + "sort" "strconv" "time" ) +var ( + MaxDelay = 9999 * time.Millisecond + MinDelay = time.Duration(0) + + InputMaxDelay = MaxDelay + InputMinDelay = MinDelay +) + type PingData struct { IP net.IPAddr - Count int + Sended int Received int Delay time.Duration } @@ -24,12 +33,23 @@ type CloudflareIPData struct { func (cf *CloudflareIPData) getRecvRate() float32 { if cf.recvRate == 0 { - pingLost := cf.Count - cf.Received - cf.recvRate = float32(pingLost) / float32(cf.Count) + pingLost := cf.Sended - cf.Received + cf.recvRate = float32(pingLost) / float32(cf.Sended) } return cf.recvRate } +func (cf *CloudflareIPData) toString() []string { + result := make([]string, 6) + result[0] = cf.IP.String() + result[1] = strconv.Itoa(cf.Sended) + result[2] = strconv.Itoa(cf.Received) + result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) + result[4] = cf.Delay.String() + result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32) + return result +} + func ExportCsv(filePath string, data []CloudflareIPData) { fp, err := os.Create(filePath) if err != nil { @@ -43,17 +63,6 @@ func ExportCsv(filePath string, data []CloudflareIPData) { w.Flush() } -func (cf *CloudflareIPData) toString() []string { - result := make([]string, 6) - result[0] = cf.IP.String() - result[1] = strconv.Itoa(cf.Count) - result[2] = strconv.Itoa(cf.Received) - result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) - result[4] = cf.Delay.String() - result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32) - return result -} - func convertToString(data []CloudflareIPData) [][]string { result := make([][]string, 0) for _, v := range data { @@ -61,3 +70,53 @@ func convertToString(data []CloudflareIPData) [][]string { } return result } + +type PingDelaySet []CloudflareIPData + +func (s PingDelaySet) FilterDelay() (data PingDelaySet) { + sort.Sort(s) + if InputMaxDelay >= MaxDelay || InputMinDelay <= MinDelay { + return s + } + for _, v := range s { + if v.Delay > MaxDelay { // 平均延迟上限 + break + } + if v.Delay <= MinDelay { // 平均延迟下限 + continue + } + data = append(data, v) // 延迟满足条件时,添加到新数组中 + } + return +} + +func (s PingDelaySet) Len() int { + return len(s) +} + +func (s PingDelaySet) Less(i, j int) bool { + iRate, jRate := s[i].getRecvRate(), s[j].getRecvRate() + if iRate != jRate { + return iRate < jRate + } + return s[i].Delay < s[j].Delay +} + +func (s PingDelaySet) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// 下载速度排序 +type DownloadSpeedSet []CloudflareIPData + +func (s DownloadSpeedSet) Len() int { + return len(s) +} + +func (s DownloadSpeedSet) Less(i, j int) bool { + return s[i].downloadSpeed > s[j].downloadSpeed +} + +func (s DownloadSpeedSet) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} diff --git a/utils/progress.go b/utils/progress.go index cf14e271..5fc3be57 100644 --- a/utils/progress.go +++ b/utils/progress.go @@ -11,13 +11,21 @@ const ( ) type Bar struct { - *pb.ProgressBar + pb *pb.ProgressBar } func NewBar(count int) *Bar { return &Bar{pb.Simple.Start(count)} } +func (b *Bar) Grow(num int) { + b.pb.Add(num) +} + +func (b *Bar) Done() { + b.pb.Finish() +} + func handleProgressGenerator(pb *pb.ProgressBar) func(e ProgressEvent) { return func(e ProgressEvent) { switch e { From f1a9b5c9661518879245572423e08f73053559cd Mon Sep 17 00:00:00 2001 From: mazhuang Date: Wed, 10 Nov 2021 17:12:12 +0800 Subject: [PATCH 05/22] rebuild download --- IPRangeLoader.go | 7 +- main.go | 252 +++++++++++++--------------------------------- task/download.go | 149 +++++++++++++++++++++++++++ task/ip.go | 4 + task/tcping.go | 32 ++++-- tcping.go | 167 ------------------------------ utils/csv.go | 43 ++++++-- utils/progress.go | 23 +---- 8 files changed, 287 insertions(+), 390 deletions(-) create mode 100644 task/download.go delete mode 100644 tcping.go diff --git a/IPRangeLoader.go b/IPRangeLoader.go index 2dc00aa7..b1442630 100644 --- a/IPRangeLoader.go +++ b/IPRangeLoader.go @@ -1,6 +1,7 @@ package main import ( + "CloudflareSpeedTest/task" "bufio" "log" "net" @@ -65,7 +66,7 @@ func loadFirstIPOfRangeFromFile(ipFile string) []net.IPAddr { for scanner.Scan() { IPString := scanner.Text() if !strings.Contains(IPString, "/") { // 如果不含有 / 则代表不是 IP 段,而是一个单独的 IP,因此需要加上 /32 /128 子网掩码 - if ipv6Mode { + if task.IPv6 { IPString += "/128" } else { IPString += "/32" @@ -77,12 +78,12 @@ func loadFirstIPOfRangeFromFile(ipFile string) []net.IPAddr { if err != nil { log.Fatal(err) } - if !ipv6Mode { // IPv4 + if !task.IPv6 { // IPv4 minIP, maxIP := getCidrIPRange(IPString) // 获取 IP 最后一段最小值和最大值 Mask, _ := strconv.Atoi(strings.Split(IPString, "/")[1]) // 获取子网掩码 MaxIPNum := getCidrHostNum(Mask) // 根据子网掩码获取主机数量 for IPRange.Contains(firstIP) { - if allip { // 如果是测速全部 IP + if task.TestAll { // 如果是测速全部 IP for i := minIP; i <= maxIP; i++ { // 遍历 IP 最后一段最小值到最大值 firstIP[15] = i firstIPCopy := make([]byte, len(firstIP)) diff --git a/main.go b/main.go index 3b3a621b..fe82167b 100644 --- a/main.go +++ b/main.go @@ -7,20 +7,14 @@ import ( "net/http" "os" "runtime" - "sort" - "sync" "time" "CloudflareSpeedTest/task" - - "github.com/cheggaaa/pb/v3" + "CloudflareSpeedTest/utils" ) var ( - version, ipFile, outputFile, versionNew string - disableDownload, ipv6Mode, allip bool - tcpPort, printResultNum, downloadSecond int - timeLimit, timeLimitLow, speedLimit float64 + version, versionNew string ) func init() { @@ -67,27 +61,23 @@ https://github.com/XIU2/CloudflareSpeedTest 打印帮助说明 ` - flag.IntVar(&pingRoutine, "n", 200, "测速线程数量") - flag.IntVar(&pingTime, "t", 4, "延迟测速次数") - flag.IntVar(&tcpPort, "tp", 443, "延迟测速端口") - flag.IntVar(&downloadTestCount, "dn", 20, "下载测速数量") - flag.IntVar(&downloadSecond, "dt", 10, "下载测速时间") - flag.StringVar(&url, "url", "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png", "下载测速地址") - flag.Float64Var(&timeLimit, "tl", 9999, "平均延迟上限") - flag.Float64Var(&timeLimitLow, "tll", 0, "平均延迟下限") - flag.Float64Var(&speedLimit, "sl", 0, "下载速度下限") - flag.IntVar(&printResultNum, "p", 20, "显示结果数量") - flag.BoolVar(&disableDownload, "dd", false, "禁用下载测速") - flag.BoolVar(&ipv6Mode, "ipv6", false, "启用IPv6") - flag.BoolVar(&allip, "allip", false, "测速全部 IP") - flag.StringVar(&ipFile, "f", "ip.txt", "IP 数据文件") - flag.StringVar(&outputFile, "o", "result.csv", "输出结果文件") + flag.IntVar(&task.Routines, "n", 200, "测速线程数量") + flag.IntVar(&task.PingTimes, "t", 4, "延迟测速次数") + flag.IntVar(&task.TCPPort, "tp", 443, "延迟测速端口") + flag.DurationVar(&utils.InputMaxDelay, "tl", 9999*time.Millisecond, "平均延迟上限") + flag.DurationVar(&utils.InputMinDelay, "tll", time.Duration(0), "平均延迟下限") + flag.DurationVar(&task.Timeout, "dt", 10*time.Second, "下载测速时间") + flag.IntVar(&task.TestCount, "dn", 20, "下载测速数量") + flag.StringVar(&task.URL, "url", "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png", "下载测速地址") + flag.BoolVar(&task.Disable, "dd", false, "禁用下载测速") + flag.BoolVar(&task.IPv6, "ipv6", false, "启用IPv6") + flag.BoolVar(&task.TestAll, "allip", false, "测速全部 IP") + flag.StringVar(&task.IPFile, "f", "ip.txt", "IP 数据文件") + flag.Float64Var(&task.MinSpeed, "sl", 0, "下载速度下限") + flag.IntVar(&utils.PrintNum, "p", 20, "显示结果数量") + flag.StringVar(&utils.Output, "o", "result.csv", "输出结果文件") flag.BoolVar(&printVersion, "v", false, "打印程序版本") - task.TCPPort = tcpPort - task.IPv6 = ipv6Mode - task.DefaultRoutine = pingRoutine - flag.Usage = func() { fmt.Print(help) } flag.Parse() if printVersion { @@ -101,184 +91,80 @@ https://github.com/XIU2/CloudflareSpeedTest } os.Exit(0) } - if pingRoutine <= 0 { - pingRoutine = 200 - } - if pingTime <= 0 { - pingTime = 4 - } - if tcpPort < 1 || tcpPort > 65535 { - tcpPort = 443 - } - if downloadTestCount <= 0 { - downloadTestCount = 20 - } - if downloadSecond <= 0 { - downloadSecond = 10 - } - if url == "" { - url = "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png" - } - if timeLimit <= 0 || timeLimit > 9999 { - timeLimit = 9999 - } - if timeLimitLow < 0 || timeLimitLow > 9999 { - timeLimitLow = 0 - } - if speedLimit < 0 { - speedLimit = 0 - } - if printResultNum < 0 { - printResultNum = 20 - } - if ipFile == "" { - ipFile = "ip.txt" - } - if outputFile == " " { - outputFile = "" - } } func main() { go checkUpdate() // 检查版本更新 initRandSeed() // 置随机数种子 - failTime = pingTime // 设置接收次数 - ips := loadFirstIPOfRangeFromFile(ipFile) // 读入IP - pingCount := len(ips) * pingTime // 计算进度条总数(IP*测试次数) - bar := pb.Simple.Start(pingCount) // 进度条总数 - var ( - wg sync.WaitGroup - mu sync.Mutex - data = make([]CloudflareIPData, 0) - data2 = make([]CloudflareIPData, 0) - ) - downloadTestTime = time.Duration(downloadSecond) * time.Second + ips := loadFirstIPOfRangeFromFile(task.IPFile) // 读入IP // 开始延迟测速 fmt.Printf("# XIU2/CloudflareSpeedTest %s \n", version) ipVersion := "IPv4" - if ipv6Mode { // IPv6 模式判断 + if task.IPv6 { // IPv6 模式判断 ipVersion = "IPv6" } - fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%.2f ms,平均延迟下限:%.2f ms):\n", ipVersion, tcpPort, timeLimit, timeLimitLow) - - // ping := task.NewPing(ips) - // ping.Run() - control := make(chan bool, pingRoutine) - for _, ip := range ips { - wg.Add(1) - control <- false - handleProgress := handleProgressGenerator(bar) // 多线程进度条 - go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress) - } - wg.Wait() - bar.Finish() - // data := ping.Data() - // sort.Sort(utils.CloudflareIPDataSet(data)) - sort.Sort(CloudflareIPDataSet(data)) // 排序(按延迟,从低到高,不同丢包率会分开单独按延迟和丢包率排序) - - // 延迟测速完毕后,以 [平均延迟上限] + [平均延迟下限] 条件过滤结果 - if timeLimit != 9999 || timeLimitLow != 0 { - for i := 0; i < len(data); i++ { - if float64(data[i].pingTime) > timeLimit { // 平均延迟上限 - break - } - if float64(data[i].pingTime) <= timeLimitLow { // 平均延迟下限 - continue - } - data2 = append(data2, data[i]) // 延迟满足条件时,添加到新数组中 - } - data = data2 - data2 = []CloudflareIPData{} - } - - // 开始下载测速 - if !disableDownload { // 如果禁用下载测速就跳过 - testDownloadSpeed(data, data2, bar) - } - - if len(data2) > 0 { // 如果该数组有内容,说明指定了 [下载测速下限] 条件,且最少有 1 个满足条件的 IP - data = data2 - } - sort.Sort(CloudflareIPDataSetD(data)) // 排序(按下载速度,从高到低) - if outputFile != "" { - ExportCsv(outputFile, data) // 输出结果到文件 - } - printResult(data) // 显示最快结果 -} + fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%v,平均延迟下限:%v)\n", ipVersion, task.TCPPort, utils.InputMaxDelay, utils.InputMinDelay) -func testDownloadSpeed(data, data2 []CloudflareIPData, bar *pb.ProgressBar) { - if len(data) <= 0 { // IP数组长度(IP数量) 大于 0 时才会继续下载测速 - fmt.Println("\n[信息] 延迟测速结果 IP 数量为 0,跳过下载测速。") - return - } - if len(data) < downloadTestCount { // 如果IP数组长度(IP数量) 小于下载测速数量(-dn),则次数修正为IP数 - downloadTestCount = len(data) - } - // 临时的下载测速次数,即实际的下载测速数量 - downloadTestCount2 := downloadTestCount - // 如果没有指定 [下载速度下限] 条件,则临时变量为下载测速数量(-dn) - if speedLimit > 0 { - // 如果指定了 [下载速度下限] 条件,则临时变量改为总数量(即一直测速下去,直到凑够下载测速数量 -dn) - downloadTestCount2 = len(data) - } - fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", speedLimit, downloadTestCount, downloadTestCount2) - bar = pb.Simple.Start(downloadTestCount) - for i := 0; i < downloadTestCount2; i++ { - _, speed := DownloadSpeedHandler(data[i].ip) - data[i].downloadSpeed = speed - // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 - if float64(speed) >= speedLimit*1024*1024 { - data2 = append(data2, data[i]) // 高于下载速度下限时,添加到新数组中 - bar.Add(1) - if len(data2) == downloadTestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 - break - } - } - } - bar.Finish() -} - -// 显示最快结果 -func printResult(data []CloudflareIPData) { - sysType := runtime.GOOS - if printResultNum <= 0 { // 如果禁止直接输出结果就跳过 - fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", outputFile) - return - } - dateString := convertToString(data) // 转为多维数组 [][]String - if len(dateString) <= 0 { // IP数组长度(IP数量) 大于 0 时继续 - fmt.Println("\n[信息] 完整测速结果 IP 数量为 0,跳过输出结果。") - return - } - if len(dateString) < printResultNum { // 如果IP数组长度(IP数量) 小于 打印次数,则次数改为IP数量 - printResultNum = len(dateString) - } - resHeader := []interface{}{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"} - if ipv6Mode { // IPv6 太长了,所以需要调整一下间隔 - fmt.Printf("%-40s%-5s%-5s%-5s%-6s%-11s\n", resHeader...) - for i := 0; i < printResultNum; i++ { - fmt.Printf("%-42s%-8s%-8s%-8s%-10s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) - } - } else { - fmt.Printf("%-16s%-5s%-5s%-5s%-6s%-11s\n", resHeader...) - for i := 0; i < printResultNum; i++ { - fmt.Printf("%-18s%-8s%-8s%-8s%-15s%-15s\n", ipPadding(dateString[i][0]), dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) - } - } + pingData := task.NewPing(ips).Run().FilterDelay() + speedData := task.TestDownloadSpeed(pingData) + utils.ExportCsv(speedData) + speedData.Print(task.IPv6) if versionNew != "" { fmt.Printf("\n*** 发现新版本 [%s]!请前往 [https://github.com/XIU2/CloudflareSpeedTest] 更新! ***\n", versionNew) } - if outputFile != "" { - fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", outputFile) + if utils.Output != "" { + fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", utils.Output) } - if sysType == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) + if runtime.GOOS == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) fmt.Printf("按下 回车键 或 Ctrl+C 退出。\n") var pause int fmt.Scanln(&pause) } + + // control := make(chan bool, pingRoutine) + // for _, ip := range ips { + // wg.Add(1) + // control <- false + // handleProgress := handleProgressGenerator(bar) // 多线程进度条 + // go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress) + // } + // wg.Wait() + // bar.Finish() + // data := ping.Data() + // sort.Sort(utils.CloudflareIPDataSet(data)) + // sort.Sort(CloudflareIPDataSet(data)) // 排序(按延迟,从低到高,不同丢包率会分开单独按延迟和丢包率排序) + + // 延迟测速完毕后,以 [平均延迟上限] + [平均延迟下限] 条件过滤结果 + // if timeLimit != 9999 || timeLimitLow != 0 { + // for i := 0; i < len(data); i++ { + // if float64(data[i].pingTime) > timeLimit { // 平均延迟上限 + // break + // } + // if float64(data[i].pingTime) <= timeLimitLow { // 平均延迟下限 + // continue + // } + // data2 = append(data2, data[i]) // 延迟满足条件时,添加到新数组中 + // } + // data = data2 + // data2 = []CloudflareIPData{} + // } + + // 开始下载测速 + // if !disableDownload { // 如果禁用下载测速就跳过 + // testDownloadSpeed(data, data2, bar) + // } + + // if len(data2) > 0 { // 如果该数组有内容,说明指定了 [下载测速下限] 条件,且最少有 1 个满足条件的 IP + // data = data2 + // } + // sort.Sort(CloudflareIPDataSetD(data)) // 排序(按下载速度,从高到低) + // if outputFile != "" { + // ExportCsv(outputFile, data) // 输出结果到文件 + // } + // printResult(data) // 显示最快结果 } // 检查更新 diff --git a/task/download.go b/task/download.go new file mode 100644 index 00000000..072c6150 --- /dev/null +++ b/task/download.go @@ -0,0 +1,149 @@ +package task + +import ( + "context" + "fmt" + "io" + "net" + "net/http" + "sort" + "time" + + "CloudflareSpeedTest/utils" + + "github.com/VividCortex/ewma" +) + +const ( + bufferSize = 1024 + defaultURL = "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png" + defaultTimeout = 10 * time.Second + defaultDisableDownlaod = false + defaultTestNum = 20 + defaultMinSpeed float64 = 0.0 +) + +var ( + // download test url + URL = defaultURL + // download timeout + Timeout = defaultTimeout + // disable download + Disable = defaultDisableDownlaod + + TestCount = defaultTestNum + MinSpeed = defaultMinSpeed +) + +func checkDownloadDefault() { + if URL == "" { + URL = defaultURL + } + if Timeout <= 0 { + Timeout = defaultTimeout + } + if TestCount <= 0 { + TestCount = defaultTestNum + } + if MinSpeed <= 0.0 { + MinSpeed = defaultMinSpeed + } +} + +func TestDownloadSpeed(ipSet utils.PingDelaySet) (sppedSet utils.DownloadSpeedSet) { + checkDownloadDefault() + if Disable { + return utils.DownloadSpeedSet(ipSet) + } + if len(ipSet) <= 0 { // IP数组长度(IP数量) 大于 0 时才会继续下载测速 + fmt.Println("\n[信息] 延迟测速结果 IP 数量为 0,跳过下载测速。") + return + } + testNum := TestCount + if len(ipSet) < TestCount || MinSpeed > 0 { // 如果IP数组长度(IP数量) 小于下载测速数量(-dn),则次数修正为IP数 + testNum = len(ipSet) + } + + fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum) + bar := utils.NewBar(TestCount) + for i := 0; i < testNum; i++ { + speed := downloadSpeedHandler(&ipSet[i].IP) + ipSet[i].DownloadSpeed = speed + // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 + if speed >= MinSpeed*1024*1024 { + sppedSet = append(sppedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中 + bar.Grow(1) + if len(sppedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 + break + } + } + } + bar.Done() + // 按速度排序 + sort.Sort(sppedSet) + return +} + +func getDialContext(ip *net.IPAddr) func(ctx context.Context, network, address string) (net.Conn, error) { + fakeSourceAddr := ip.String() + ":443" + if IPv6 { // IPv6 需要加上 [] + fakeSourceAddr = "[" + ip.String() + "]:443" + } + return func(ctx context.Context, network, address string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, network, fakeSourceAddr) + } +} + +//bool : can download,float32 downloadSpeed +func downloadSpeedHandler(ip *net.IPAddr) float64 { + client := &http.Client{ + Transport: &http.Transport{DialContext: getDialContext(ip)}, + Timeout: Timeout, + } + response, err := client.Get(URL) + if err != nil { + return 0.0 + } + defer response.Body.Close() + if response.StatusCode != 200 { + return 0.0 + } + timeStart := time.Now() + timeEnd := timeStart.Add(Timeout) + + contentLength := response.ContentLength + buffer := make([]byte, bufferSize) + + var ( + contentRead int64 = 0 + timeSlice = Timeout / 100 + timeCounter = 1 + lastContentRead int64 = 0 + ) + + var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) + e := ewma.NewMovingAverage() + + for contentLength != contentRead { + currentTime := time.Now() + if currentTime.After(nextTime) { + timeCounter++ + nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) + e.Add(float64(contentRead - lastContentRead)) + lastContentRead = contentRead + } + if currentTime.After(timeEnd) { + break + } + bufferRead, err := response.Body.Read(buffer) + contentRead += int64(bufferRead) + if err != nil { + if err != io.EOF { + break + } + e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice))) + } + } + return e.Value() / (Timeout.Seconds() / 120) + +} diff --git a/task/ip.go b/task/ip.go index 5815c5a4..c2ff808c 100644 --- a/task/ip.go +++ b/task/ip.go @@ -3,4 +3,8 @@ package task var ( // IPv6 IP version is 6 IPv6 = false + // TestAll test all ip + TestAll = false + // IPFile is the filename of IP Rangs + IPFile = "ip.txt" ) diff --git a/task/tcping.go b/task/tcping.go index b065e9d9..9795f0b9 100644 --- a/task/tcping.go +++ b/task/tcping.go @@ -3,6 +3,7 @@ package task import ( "fmt" "net" + "sort" "sync" "time" @@ -12,12 +13,15 @@ import ( const ( tcpConnectTimeout = time.Second * 1 maxRoutine = 1000 + defaultRoutines = 200 + defaultPort = 443 + defaultPingTimes = 4 ) var ( - DefaultRoutine = 200 - TCPPort int = 443 - PingTimes int = 4 + Routines = defaultRoutines + TCPPort int = defaultPort + PingTimes int = defaultPingTimes ) type Ping struct { @@ -29,14 +33,27 @@ type Ping struct { bar *utils.Bar } +func checkPingDefault() { + if Routines <= 0 { + Routines = defaultRoutines + } + if TCPPort <= 0 || TCPPort >= 65535 { + TCPPort = defaultPort + } + if PingTimes <= 0 { + PingTimes = defaultPingTimes + } +} + func NewPing(ips []net.IPAddr) *Ping { + checkPingDefault() return &Ping{ wg: &sync.WaitGroup{}, m: &sync.Mutex{}, ips: ips, csv: make(utils.PingDelaySet, 0), - control: make(chan bool, DefaultRoutine), - bar: utils.NewBar(len(ips) * PingTimes), + control: make(chan bool, Routines), + bar: utils.NewBar(len(ips)), } } @@ -48,6 +65,7 @@ func (p *Ping) Run() utils.PingDelaySet { } p.wg.Wait() p.bar.Done() + sort.Sort(p.csv) return p.csv } @@ -112,7 +130,7 @@ func (p *Ping) tcpingHandler(ip net.IPAddr) { break } } - p.bar.Grow(PingTimes) + p.bar.Grow(1) if !ipCanConnect { return } @@ -126,7 +144,7 @@ func (p *Ping) tcpingHandler(ip net.IPAddr) { // } data := &utils.PingData{ IP: ip, - Sended: PingTimes, + Sended: PingTimes, Received: pingRecv, Delay: delay / time.Duration(pingRecv), } diff --git a/tcping.go b/tcping.go deleted file mode 100644 index 1cbacd00..00000000 --- a/tcping.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io" - "net" - "net/http" - "sync" - "time" - - "github.com/VividCortex/ewma" -) - -//bool connectionSucceed float32 time -func tcping(ip net.IPAddr, tcpPort int) (bool, time.Duration) { - startTime := time.Now() - fullAddress := fmt.Sprintf("%s:%d", ip.String(), tcpPort) - //fmt.Println(ip.String()) - if ipv6Mode { // IPv6 需要加上 [] - fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), tcpPort) - } - conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout) - if err != nil { - return false, 0 - } - defer conn.Close() - duration := time.Since(startTime) - return true, duration -} - -//pingReceived pingTotalTime -func checkConnection(ip net.IPAddr, tcpPort int) (pingRecv int, pingTime time.Duration) { - for i := 1; i <= failTime; i++ { - pingSucceed, pingTimeCurrent := tcping(ip, tcpPort) - if pingSucceed { - pingRecv++ - pingTime += pingTimeCurrent - } - } - return -} - -//return Success packetRecv averagePingTime specificIPAddr -func tcpingHandler(ip net.IPAddr, tcpPort, pingCount int, progressHandler func(e progressEvent)) (bool, int, time.Duration, net.IPAddr) { - ipCanConnect := false - pingRecv := 0 - var pingTime time.Duration - for !ipCanConnect { - pingRecvCurrent, pingTimeCurrent := checkConnection(ip, tcpPort) - if pingRecvCurrent != 0 { - ipCanConnect = true - pingRecv = pingRecvCurrent - pingTime = pingTimeCurrent - } else { - ip.IP[15]++ - if ip.IP[15] == 0 { - break - } - break - } - } - if !ipCanConnect { - progressHandler(NoAvailableIPFound) - return false, 0, 0, net.IPAddr{} - } - progressHandler(AvailableIPFound) - for i := failTime; i < pingCount; i++ { - fmt.Println("failTime", failTime) - pingSuccess, pingTimeCurrent := tcping(ip, tcpPort) - progressHandler(NormalPing) - if pingSuccess { - pingRecv++ - pingTime += pingTimeCurrent - } - } - return true, pingRecv, pingTime / time.Duration(pingRecv), ip -} - -func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, tcpPort int, pingCount int, csv *[]CloudflareIPData, control chan bool, progressHandler func(e progressEvent)) { - defer wg.Done() - // fmt.Println(ip.String()) - success, pingRecv, pingTimeAvg, currentIP := tcpingHandler(ip, tcpPort, pingCount, progressHandler) - if success { - mutex.Lock() - var cfdata CloudflareIPData - cfdata.ip = currentIP - cfdata.pingReceived = pingRecv - cfdata.pingTime = pingTimeAvg - cfdata.pingCount = pingCount - *csv = append(*csv, cfdata) - mutex.Unlock() - } - <-control -} - -func GetDialContextByAddr(fakeSourceAddr string) func(ctx context.Context, network, address string) (net.Conn, error) { - return func(ctx context.Context, network, address string) (net.Conn, error) { - c, e := (&net.Dialer{}).DialContext(ctx, network, fakeSourceAddr) - return c, e - } -} - -//bool : can download,float32 downloadSpeed -func DownloadSpeedHandler(ip net.IPAddr) (bool, float32) { - var client = http.Client{ - Transport: nil, - CheckRedirect: nil, - Jar: nil, - Timeout: downloadTestTime, - } - var fullAddress string - if ipv6Mode { // IPv6 需要加上 [] - fullAddress = "[" + ip.String() + "]:443" - } else { - fullAddress = ip.String() + ":443" - } - client.Transport = &http.Transport{ - DialContext: GetDialContextByAddr(fullAddress), - } - response, err := client.Get(url) - if err != nil { - return false, 0 - } - defer response.Body.Close() - if response.StatusCode != 200 { - return false, 0 - } - timeStart := time.Now() - timeEnd := timeStart.Add(downloadTestTime) - - contentLength := response.ContentLength - buffer := make([]byte, downloadBufferSize) - - var ( - contentRead int64 = 0 - timeSlice = downloadTestTime / 100 - timeCounter = 1 - lastContentRead int64 = 0 - ) - - var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) - e := ewma.NewMovingAverage() - - for contentLength != contentRead { - var currentTime = time.Now() - if currentTime.After(nextTime) { - timeCounter++ - nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter)) - e.Add(float64(contentRead - lastContentRead)) - lastContentRead = contentRead - } - if currentTime.After(timeEnd) { - break - } - bufferRead, err := response.Body.Read(buffer) - contentRead += int64(bufferRead) - if err != nil { - if err != io.EOF { - break - } - e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice))) - } - } - return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120) - -} diff --git a/utils/csv.go b/utils/csv.go index f93452d5..651cb699 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -2,20 +2,24 @@ package utils import ( "encoding/csv" + "fmt" "log" "net" "os" - "sort" "strconv" "time" ) +const defaultOutput = "result.csv" + var ( MaxDelay = 9999 * time.Millisecond MinDelay = time.Duration(0) InputMaxDelay = MaxDelay InputMinDelay = MinDelay + Output = defaultOutput + PrintNum = 20 ) type PingData struct { @@ -28,7 +32,7 @@ type PingData struct { type CloudflareIPData struct { *PingData recvRate float32 - downloadSpeed float32 + DownloadSpeed float64 } func (cf *CloudflareIPData) getRecvRate() float32 { @@ -46,14 +50,17 @@ func (cf *CloudflareIPData) toString() []string { result[2] = strconv.Itoa(cf.Received) result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) result[4] = cf.Delay.String() - result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32) + result[5] = strconv.FormatFloat(cf.DownloadSpeed/1024/1024, 'f', 2, 32) return result } -func ExportCsv(filePath string, data []CloudflareIPData) { - fp, err := os.Create(filePath) +func ExportCsv(data []CloudflareIPData) { + if Output == "" { + Output = defaultOutput + } + fp, err := os.Create(Output) if err != nil { - log.Fatalf("创建文件[%s]失败:%v", filePath, err) + log.Fatalf("创建文件[%s]失败:%v", Output, err) return } defer fp.Close() @@ -74,7 +81,6 @@ func convertToString(data []CloudflareIPData) [][]string { type PingDelaySet []CloudflareIPData func (s PingDelaySet) FilterDelay() (data PingDelaySet) { - sort.Sort(s) if InputMaxDelay >= MaxDelay || InputMinDelay <= MinDelay { return s } @@ -114,9 +120,30 @@ func (s DownloadSpeedSet) Len() int { } func (s DownloadSpeedSet) Less(i, j int) bool { - return s[i].downloadSpeed > s[j].downloadSpeed + return s[i].DownloadSpeed > s[j].DownloadSpeed } func (s DownloadSpeedSet) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (s DownloadSpeedSet) Print(ipv6 bool) { + if len(s) <= 0 { // IP数组长度(IP数量) 大于 0 时继续 + fmt.Println("\n[信息] 完整测速结果 IP 数量为 0,跳过输出结果。") + return + } + dateString := convertToString(s) // 转为多维数组 [][]String + if len(dateString) < PrintNum { // 如果IP数组长度(IP数量) 小于 打印次数,则次数改为IP数量 + PrintNum = len(dateString) + } + headFormat := "%-16s%-5s%-5s%-5s%-6s%-11s\n" + dataFormat := "%-18s%-8s%-8s%-8s%-15s%-15s\n" + if ipv6 { // IPv6 太长了,所以需要调整一下间隔 + headFormat = "%-40s%-5s%-5s%-5s%-6s%-11s\n" + dataFormat = "%-42s%-8s%-8s%-8s%-10s%-15s\n" + } + fmt.Printf(headFormat, "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)") + for i := 0; i < PrintNum; i++ { + fmt.Printf(dataFormat, dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) + } +} \ No newline at end of file diff --git a/utils/progress.go b/utils/progress.go index 5fc3be57..85010c36 100644 --- a/utils/progress.go +++ b/utils/progress.go @@ -2,14 +2,6 @@ package utils import "github.com/cheggaaa/pb/v3" -type ProgressEvent int - -const ( - NoAvailableIPFound ProgressEvent = iota - AvailableIPFound - NormalPing -) - type Bar struct { pb *pb.ProgressBar } @@ -24,17 +16,4 @@ func (b *Bar) Grow(num int) { func (b *Bar) Done() { b.pb.Finish() -} - -func handleProgressGenerator(pb *pb.ProgressBar) func(e ProgressEvent) { - return func(e ProgressEvent) { - switch e { - case NoAvailableIPFound: - // pb.Add(pingTime) - case AvailableIPFound: - // pb.Add(failTime) - case NormalPing: - pb.Increment() - } - } -} +} \ No newline at end of file From 28d5d89e85999401022f6d3060f49e12fdc30592 Mon Sep 17 00:00:00 2001 From: mazhuang Date: Wed, 10 Nov 2021 18:47:21 +0800 Subject: [PATCH 06/22] rebuild load ip --- main.go | 46 +---------- task/download.go | 2 +- task/ip.go | 202 ++++++++++++++++++++++++++++++++++++++++++++++- task/tcping.go | 12 +-- utils/csv.go | 2 +- 5 files changed, 211 insertions(+), 53 deletions(-) diff --git a/main.go b/main.go index fe82167b..1beac0f7 100644 --- a/main.go +++ b/main.go @@ -95,8 +95,8 @@ https://github.com/XIU2/CloudflareSpeedTest func main() { go checkUpdate() // 检查版本更新 - initRandSeed() // 置随机数种子 - ips := loadFirstIPOfRangeFromFile(task.IPFile) // 读入IP + ips := task.LoadIPRanges() + // ips := loadFirstIPOfRangeFromFile(task.IPFile) // 读入IP // 开始延迟测速 fmt.Printf("# XIU2/CloudflareSpeedTest %s \n", version) @@ -123,48 +123,6 @@ func main() { var pause int fmt.Scanln(&pause) } - - // control := make(chan bool, pingRoutine) - // for _, ip := range ips { - // wg.Add(1) - // control <- false - // handleProgress := handleProgressGenerator(bar) // 多线程进度条 - // go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress) - // } - // wg.Wait() - // bar.Finish() - // data := ping.Data() - // sort.Sort(utils.CloudflareIPDataSet(data)) - // sort.Sort(CloudflareIPDataSet(data)) // 排序(按延迟,从低到高,不同丢包率会分开单独按延迟和丢包率排序) - - // 延迟测速完毕后,以 [平均延迟上限] + [平均延迟下限] 条件过滤结果 - // if timeLimit != 9999 || timeLimitLow != 0 { - // for i := 0; i < len(data); i++ { - // if float64(data[i].pingTime) > timeLimit { // 平均延迟上限 - // break - // } - // if float64(data[i].pingTime) <= timeLimitLow { // 平均延迟下限 - // continue - // } - // data2 = append(data2, data[i]) // 延迟满足条件时,添加到新数组中 - // } - // data = data2 - // data2 = []CloudflareIPData{} - // } - - // 开始下载测速 - // if !disableDownload { // 如果禁用下载测速就跳过 - // testDownloadSpeed(data, data2, bar) - // } - - // if len(data2) > 0 { // 如果该数组有内容,说明指定了 [下载测速下限] 条件,且最少有 1 个满足条件的 IP - // data = data2 - // } - // sort.Sort(CloudflareIPDataSetD(data)) // 排序(按下载速度,从高到低) - // if outputFile != "" { - // ExportCsv(outputFile, data) // 输出结果到文件 - // } - // printResult(data) // 显示最快结果 } // 检查更新 diff --git a/task/download.go b/task/download.go index 072c6150..bff35026 100644 --- a/task/download.go +++ b/task/download.go @@ -67,7 +67,7 @@ func TestDownloadSpeed(ipSet utils.PingDelaySet) (sppedSet utils.DownloadSpeedSe fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum) bar := utils.NewBar(TestCount) for i := 0; i < testNum; i++ { - speed := downloadSpeedHandler(&ipSet[i].IP) + speed := downloadSpeedHandler(ipSet[i].IP) ipSet[i].DownloadSpeed = speed // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 if speed >= MinSpeed*1024*1024 { diff --git a/task/ip.go b/task/ip.go index c2ff808c..d22af3c8 100644 --- a/task/ip.go +++ b/task/ip.go @@ -1,10 +1,210 @@ package task +import ( + "bufio" + "log" + "math/rand" + "net" + "os" + "strconv" + "strings" + "time" +) + +const defaultInputFile = "ip.txt" + var ( // IPv6 IP version is 6 IPv6 = false // TestAll test all ip TestAll = false // IPFile is the filename of IP Rangs - IPFile = "ip.txt" + IPFile = defaultInputFile ) + +func randipEndWith(num int) uint8 { + rand.Seed(time.Now().UnixNano()) + return uint8(rand.Intn(num)) +} + +func LoadIPRanges() []*net.IPAddr { + if IPFile == "" { + IPFile = defaultInputFile + } + file, err := os.Open(IPFile) + if err != nil { + log.Fatal(err) + } + defer file.Close() + firstIPs := make([]*net.IPAddr, 0) + scanner := bufio.NewScanner(file) + // scanner.Split(bufio.ScanLines) + for scanner.Scan() { + IPString := scanner.Text() + // 如果不含有 '/' 则代表不是 IP 段,而是一个单独的 IP,因此需要加上 /32 /128 子网掩码 + if !strings.Contains(IPString, "/") { + if IPv6 { + IPString += "/128" + } else { + IPString += "/32" + } + } + firstIP, IPRange, err := net.ParseCIDR(IPString) + // fmt.Println(firstIP) + // fmt.Println(IPRange) + if err != nil { + log.Fatal(err) + } + if IPv6 { + //IPv6 + loadIPv6(IPString, IPRange, firstIP, firstIPs) + continue + } + // IPv4 + minIP, maxIP, mask := getCidrIPRange(IPString) // 获取 IP 最后一段最小值和最大值 + maxIPNum := getCidrHostNum(mask) // 根据子网掩码获取主机数量 + for IPRange.Contains(firstIP) { + if TestAll { // 如果是测速全部 IP + for i := minIP; i <= maxIP; i++ { // 遍历 IP 最后一段最小值到最大值 + firstIP[15] = i + firstIPCopy := make([]byte, len(firstIP)) + copy(firstIPCopy, firstIP) + firstIPs = append(firstIPs, &net.IPAddr{IP: firstIPCopy}) + } + } else { // 随机 IP 的最后一段 0.0.0.X + firstIP[15] = minIP + randipEndWith(maxIPNum) + firstIPCopy := make([]byte, len(firstIP)) + copy(firstIPCopy, firstIP) + firstIPs = append(firstIPs, &net.IPAddr{IP: firstIPCopy}) + } + firstIP[14]++ // 0.0.(X+1).X + if firstIP[14] == 0 { + firstIP[13]++ // 0.(X+1).X.X + if firstIP[13] == 0 { + firstIP[12]++ // (X+1).X.X.X + } + } + } + + } + return firstIPs +} + +func loadIPv6(IPString string, IPRange *net.IPNet, firstIP net.IP, firstIPs []*net.IPAddr) { + var tempIP uint8 + for IPRange.Contains(firstIP) { + //fmt.Println(firstIP) + //fmt.Println(firstIP[0], firstIP[1], firstIP[2], firstIP[3], firstIP[4], firstIP[5], firstIP[6], firstIP[7], firstIP[8], firstIP[9], firstIP[10], firstIP[11], firstIP[12], firstIP[13], firstIP[14], firstIP[15]) + if !strings.Contains(IPString, "/128") { + firstIP[15] = randipEndWith(255) // 随机 IP 的最后一段 + firstIP[14] = randipEndWith(255) // 随机 IP 的最后一段 + } + firstIPCopy := make([]byte, len(firstIP)) + copy(firstIPCopy, firstIP) + firstIPs = append(firstIPs, &net.IPAddr{IP: firstIPCopy}) + tempIP = firstIP[13] + firstIP[13] += randipEndWith(255) + if firstIP[13] >= tempIP { + continue + } + tempIP = firstIP[12] + firstIP[12] += randipEndWith(255) + if firstIP[12] >= tempIP { + continue + } + tempIP = firstIP[11] + firstIP[11] += randipEndWith(255) + if firstIP[11] >= tempIP { + continue + } + tempIP = firstIP[10] + firstIP[10] += randipEndWith(255) + if firstIP[10] >= tempIP { + continue + } + tempIP = firstIP[9] + firstIP[9] += randipEndWith(255) + if firstIP[9] >= tempIP { + continue + } + tempIP = firstIP[8] + firstIP[8] += randipEndWith(255) + if firstIP[8] >= tempIP { + continue + } + tempIP = firstIP[7] + firstIP[7] += randipEndWith(255) + if firstIP[7] >= tempIP { + continue + } + tempIP = firstIP[6] + firstIP[6] += randipEndWith(255) + if firstIP[6] >= tempIP { + continue + } + tempIP = firstIP[5] + firstIP[5] += randipEndWith(255) + if firstIP[5] >= tempIP { + continue + } + tempIP = firstIP[4] + firstIP[4] += randipEndWith(255) + if firstIP[4] >= tempIP { + continue + } + tempIP = firstIP[3] + firstIP[3] += randipEndWith(255) + if firstIP[3] >= tempIP { + continue + } + tempIP = firstIP[2] + firstIP[2] += randipEndWith(255) + if firstIP[2] >= tempIP { + continue + } + tempIP = firstIP[1] + firstIP[1] += randipEndWith(255) + if firstIP[1] >= tempIP { + continue + } + tempIP = firstIP[0] + firstIP[0] += randipEndWith(255) + } +} + +// 根据子网掩码获取主机数量 +func getCidrHostNum(maskLen int) int { + cidrIPNum := int(0) + if maskLen < 32 { + var i int = int(32 - maskLen - 1) + for ; i >= 1; i-- { + cidrIPNum += 1 << i + } + cidrIPNum += 2 + } else { + cidrIPNum = 1 + } + if cidrIPNum > 255 { + cidrIPNum = 255 + } + return cidrIPNum +} + +// 获取 IP 最后一段最小值和最大值、子网掩码 +func getCidrIPRange(cidr string) (minIP, maxIP uint8, mask int) { + ipRange := strings.Split(cidr, "/") + ipSegs := strings.Split(ipRange[0], ".") + mask, _ = strconv.Atoi(ipRange[1]) + seg4, _ := strconv.Atoi(ipSegs[3]) + minIP, maxIP = getIPSegRange(uint8(seg4), uint8(32-mask)) + return +} + +// 根据输入的基础IP地址和CIDR掩码计算一个IP片段的区间 +func getIPSegRange(userSegIP, offset uint8) (uint8, uint8) { + var ipSegMax uint8 = 255 + netSegIP := ipSegMax << offset + segMinIP := netSegIP & userSegIP + segMaxIP := userSegIP&(255< Date: Wed, 10 Nov 2021 23:58:40 +0800 Subject: [PATCH 07/22] rebuild ip and rm old file --- IPRangeLoader.go | 177 ----------------------------------------------- main.go | 8 +-- task/download.go | 6 +- task/ip.go | 125 ++++++++++++++++++--------------- task/tcping.go | 3 +- util.go | 164 ------------------------------------------- utils/csv.go | 21 +++--- 7 files changed, 87 insertions(+), 417 deletions(-) delete mode 100644 IPRangeLoader.go delete mode 100644 util.go diff --git a/IPRangeLoader.go b/IPRangeLoader.go deleted file mode 100644 index b1442630..00000000 --- a/IPRangeLoader.go +++ /dev/null @@ -1,177 +0,0 @@ -package main - -import ( - "CloudflareSpeedTest/task" - "bufio" - "log" - "net" - "os" - "strconv" - "strings" -) - -// 根据子网掩码获取主机数量 -func getCidrHostNum(maskLen int) int { - cidrIPNum := int(0) - if maskLen < 32 { - var i int = int(32 - maskLen - 1) - for ; i >= 1; i-- { - cidrIPNum += 1 << i - } - cidrIPNum += 2 - } else { - cidrIPNum = 1 - } - if cidrIPNum > 255 { - cidrIPNum = 255 - } - return cidrIPNum -} - -// 获取 IP 最后一段最小值和最大值 -func getCidrIPRange(cidr string) (uint8, uint8) { - ip := strings.Split(cidr, "/")[0] - ipSegs := strings.Split(ip, ".") - maskLen, _ := strconv.Atoi(strings.Split(cidr, "/")[1]) - seg4MinIP, seg4MaxIP := getIPSeg4Range(ipSegs, maskLen) - //ipPrefix := ipSegs[0] + "." + ipSegs[1] + "." + ipSegs[2] + "." - - return seg4MinIP, seg4MaxIP -} - -// 获取 IP 最后一段的区间 -func getIPSeg4Range(ipSegs []string, maskLen int) (uint8, uint8) { - ipSeg, _ := strconv.Atoi(ipSegs[3]) - return getIPSegRange(uint8(ipSeg), uint8(32-maskLen)) -} - -// 根据输入的基础IP地址和CIDR掩码计算一个IP片段的区间 -func getIPSegRange(userSegIP, offset uint8) (uint8, uint8) { - var ipSegMax uint8 = 255 - netSegIP := ipSegMax << offset - segMinIP := netSegIP & userSegIP - segMaxIP := userSegIP&(255<= 1; i-- { - cidrIPNum += 1 << i - } - cidrIPNum += 2 - } else { - cidrIPNum = 1 +func getCIDRHostNum(mask uint8) (subnetNum int) { + if mask >= 32 { + return 1 } - if cidrIPNum > 255 { - cidrIPNum = 255 + + if mask < 32 { + for i := int(32 - mask - 1); i >= 1; i-- { + subnetNum += 1 << i + } + subnetNum += 2 } - return cidrIPNum + if subnetNum > 0xFF { + subnetNum = 0xFF + } + return } -// 获取 IP 最后一段最小值和最大值、子网掩码 -func getCidrIPRange(cidr string) (minIP, maxIP uint8, mask int) { - ipRange := strings.Split(cidr, "/") - ipSegs := strings.Split(ipRange[0], ".") - mask, _ = strconv.Atoi(ipRange[1]) - seg4, _ := strconv.Atoi(ipSegs[3]) +// 获取 IP 最后一段最小值和最大值、主机数量 +func getCidrIPRange(cidr string) (minIP, maxIP uint8, ipNum int) { + i := strings.IndexByte(cidr, '/') + addr := cidr[:i] + mask, _ := strconv.ParseUint(cidr[i+1:], 10, 8) + i = strings.LastIndexByte(addr, '.') + seg4, _ := strconv.ParseUint(addr[i+1:], 10, 8) minIP, maxIP = getIPSegRange(uint8(seg4), uint8(32-mask)) + ipNum = getCIDRHostNum(uint8(mask)) return } // 根据输入的基础IP地址和CIDR掩码计算一个IP片段的区间 func getIPSegRange(userSegIP, offset uint8) (uint8, uint8) { - var ipSegMax uint8 = 255 + var ipSegMax uint8 = 0xFF netSegIP := ipSegMax << offset segMinIP := netSegIP & userSegIP - segMaxIP := userSegIP&(255< cfs[j].downloadSpeed -} - -func (cfs CloudflareIPDataSetD) Swap(i, j int) { - cfs[i], cfs[j] = cfs[j], cfs[i] -} diff --git a/utils/csv.go b/utils/csv.go index a4b4d0a5..6240d722 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -10,14 +10,15 @@ import ( "time" ) -const defaultOutput = "result.csv" +const ( + defaultOutput = "result.csv" + maxDelay = 9999 * time.Millisecond + minDelay = time.Duration(0) +) var ( - MaxDelay = 9999 * time.Millisecond - MinDelay = time.Duration(0) - - InputMaxDelay = MaxDelay - InputMinDelay = MinDelay + InputMaxDelay = maxDelay + InputMinDelay = minDelay Output = defaultOutput PrintNum = 20 ) @@ -81,14 +82,14 @@ func convertToString(data []CloudflareIPData) [][]string { type PingDelaySet []CloudflareIPData func (s PingDelaySet) FilterDelay() (data PingDelaySet) { - if InputMaxDelay >= MaxDelay || InputMinDelay <= MinDelay { + if InputMaxDelay >= maxDelay || InputMinDelay <= minDelay { return s } for _, v := range s { - if v.Delay > MaxDelay { // 平均延迟上限 + if v.Delay > maxDelay { // 平均延迟上限 break } - if v.Delay <= MinDelay { // 平均延迟下限 + if v.Delay <= minDelay { // 平均延迟下限 continue } data = append(data, v) // 延迟满足条件时,添加到新数组中 @@ -146,4 +147,4 @@ func (s DownloadSpeedSet) Print(ipv6 bool) { for i := 0; i < PrintNum; i++ { fmt.Printf(dataFormat, dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) } -} \ No newline at end of file +} From fbaa312622c3a68395716e2f512817b0753551c4 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Fri, 12 Nov 2021 00:14:10 +0800 Subject: [PATCH 08/22] rebuild ipranges --- task/ip.go | 283 ++++++++++++++++++++++++++--------------------------- 1 file changed, 140 insertions(+), 143 deletions(-) diff --git a/task/ip.go b/task/ip.go index f3e4d1e1..eb55937f 100644 --- a/task/ip.go +++ b/task/ip.go @@ -2,6 +2,7 @@ package task import ( "bufio" + "fmt" "log" "math/rand" "net" @@ -22,200 +23,196 @@ var ( IPFile = defaultInputFile ) -func randipEndWith(num int) uint8 { +func randIPEndWith(num byte) byte { rand.Seed(time.Now().UnixNano()) - return uint8(rand.Intn(num)) + return byte(rand.Intn(int(num))) } -func loadIPRanges() []*net.IPAddr { - if IPFile == "" { - IPFile = defaultInputFile - } - file, err := os.Open(IPFile) - if err != nil { - log.Fatal(err) +type IPRanges struct { + ips []*net.IPAddr + mask string + firstIP net.IP + ipNet *net.IPNet +} + +func newIPRanges() *IPRanges { + return &IPRanges{ + ips: make([]*net.IPAddr, 0), } - defer file.Close() - firstIPs := make([]*net.IPAddr, 0) - scanner := bufio.NewScanner(file) - for scanner.Scan() { - ipString := scanner.Text() - // 如果不含有 '/' 则代表不是 IP 段,而是一个单独的 IP,因此需要加上 /32 /128 子网掩码 - if !strings.Contains(ipString, "/") { - mask := "/32" - if IPv6 { - mask = "/128" - } - ipString += mask - } +} + +func (r *IPRanges) fixIP(ip string) string { + // 如果不含有 '/' 则代表不是 IP 段,而是一个单独的 IP,因此需要加上 /32 /128 子网掩码 + if i := strings.IndexByte(ip, '/'); i < 0 { + r.mask = "/32" if IPv6 { - //IPv6 - firstIPs = append(firstIPs, loadIPv6(ipString)...) - continue + r.mask = "/128" } - // IPv4 - firstIPs = append(firstIPs, loadIPv4(ipString)...) + ip += r.mask + } else { + r.mask = ip[i:] } - return firstIPs + return ip } -func loadIPv4(ipString string) (firstIPs []*net.IPAddr) { - firstIP, IPRange, err := net.ParseCIDR(ipString) - // fmt.Println(firstIP) - // fmt.Println(IPRange) - if err != nil { - log.Fatal(err) +func (r *IPRanges) parseCIDR(ip string) { + var err error + if r.firstIP, r.ipNet, err = net.ParseCIDR(r.fixIP(ip)); err != nil { + log.Fatalln("ParseCIDR err", err) + } +} + +func (r *IPRanges) appendIPv4(d byte) { + r.appendIP(net.IPv4(r.firstIP[12], r.firstIP[13], r.firstIP[14], d)) +} + +func (r *IPRanges) appendIP(ip net.IP) { + r.ips = append(r.ips, &net.IPAddr{IP: ip}) +} + +// 返回第四段 ip 的最小值及可用数目 +func (r *IPRanges) getIPRange() (minIP, hosts byte) { + minIP = r.firstIP[15] & r.ipNet.Mask[3] // IP 第四段最小值 + + // 根据子网掩码获取主机数量 + m := net.IPv4Mask(255, 255, 255, 255) + for i, v := range r.ipNet.Mask { + m[i] ^= v + } + total, _ := strconv.ParseInt(m.String(), 16, 32) // 总可用 IP 数 + if total > 255 { // 矫正 第四段 可用 IP 数 + hosts = 255 + return + } + if total == 0 { + hosts = 1 + return } - minIP, maxIP, hostNum := getCidrIPRange(ipString) // 获取 IP 最后一段最小值和最大值 - for IPRange.Contains(firstIP) { + hosts = byte(total) + return +} + +func (r *IPRanges) chooseIPv4() { + minIP, hosts := r.getIPRange() + fmt.Println(minIP, hosts) + for r.ipNet.Contains(r.firstIP) { if TestAll { // 如果是测速全部 IP - for i := minIP; i <= maxIP; i++ { // 遍历 IP 最后一段最小值到最大值 - firstIP[15] = i - firstIPCopy := make([]byte, len(firstIP)) - copy(firstIPCopy, firstIP) - firstIPs = append(firstIPs, &net.IPAddr{IP: firstIPCopy}) + for i := byte(0); i <= hosts; i++ { // 遍历 IP 最后一段最小值到最大值 + r.appendIPv4(i + minIP) } } else { // 随机 IP 的最后一段 0.0.0.X - firstIP[15] = minIP + randipEndWith(hostNum) - firstIPCopy := make([]byte, len(firstIP)) - copy(firstIPCopy, firstIP) - firstIPs = append(firstIPs, &net.IPAddr{IP: firstIPCopy}) - } - firstIP[14]++ // 0.0.(X+1).X - if firstIP[14] == 0 { - firstIP[13]++ // 0.(X+1).X.X - if firstIP[13] == 0 { - firstIP[12]++ // (X+1).X.X.X + r.appendIPv4(minIP + randIPEndWith(hosts)) + } + r.firstIP[14]++ // 0.0.(X+1).X + if r.firstIP[14] == 0 { + r.firstIP[13]++ // 0.(X+1).X.X + if r.firstIP[13] == 0 { + r.firstIP[12]++ // (X+1).X.X.X } } } - return } -func loadIPv6(ipString string) (firstIPs []*net.IPAddr) { - firstIP, IPRange, err := net.ParseCIDR(ipString) - // fmt.Println(firstIP) - // fmt.Println(IPRange) - if err != nil { - log.Fatal(err) - } +func (r *IPRanges) chooseIPv6() { var tempIP uint8 - for IPRange.Contains(firstIP) { + for r.ipNet.Contains(r.firstIP) { //fmt.Println(firstIP) //fmt.Println(firstIP[0], firstIP[1], firstIP[2], firstIP[3], firstIP[4], firstIP[5], firstIP[6], firstIP[7], firstIP[8], firstIP[9], firstIP[10], firstIP[11], firstIP[12], firstIP[13], firstIP[14], firstIP[15]) - if !strings.Contains(ipString, "/128") { - firstIP[15] = randipEndWith(255) // 随机 IP 的最后一段 - firstIP[14] = randipEndWith(255) // 随机 IP 的最后一段 - } - firstIPCopy := make([]byte, len(firstIP)) - copy(firstIPCopy, firstIP) - firstIPs = append(firstIPs, &net.IPAddr{IP: firstIPCopy}) - tempIP = firstIP[13] - firstIP[13] += randipEndWith(255) - if firstIP[13] >= tempIP { + if r.mask == "/128" { + r.firstIP[15] = randIPEndWith(255) // 随机 IP 的最后一段 + r.firstIP[14] = randIPEndWith(255) // 随机 IP 的最后一段 + } + firstIPCopy := make([]byte, len(r.firstIP)) + copy(firstIPCopy, r.firstIP) + r.appendIP(firstIPCopy) + tempIP = r.firstIP[13] + r.firstIP[13] += randIPEndWith(255) + if r.firstIP[13] >= tempIP { continue } - tempIP = firstIP[12] - firstIP[12] += randipEndWith(255) - if firstIP[12] >= tempIP { + tempIP = r.firstIP[12] + r.firstIP[12] += randIPEndWith(255) + if r.firstIP[12] >= tempIP { continue } - tempIP = firstIP[11] - firstIP[11] += randipEndWith(255) - if firstIP[11] >= tempIP { + tempIP = r.firstIP[11] + r.firstIP[11] += randIPEndWith(255) + if r.firstIP[11] >= tempIP { continue } - tempIP = firstIP[10] - firstIP[10] += randipEndWith(255) - if firstIP[10] >= tempIP { + tempIP = r.firstIP[10] + r.firstIP[10] += randIPEndWith(255) + if r.firstIP[10] >= tempIP { continue } - tempIP = firstIP[9] - firstIP[9] += randipEndWith(255) - if firstIP[9] >= tempIP { + tempIP = r.firstIP[9] + r.firstIP[9] += randIPEndWith(255) + if r.firstIP[9] >= tempIP { continue } - tempIP = firstIP[8] - firstIP[8] += randipEndWith(255) - if firstIP[8] >= tempIP { + tempIP = r.firstIP[8] + r.firstIP[8] += randIPEndWith(255) + if r.firstIP[8] >= tempIP { continue } - tempIP = firstIP[7] - firstIP[7] += randipEndWith(255) - if firstIP[7] >= tempIP { + tempIP = r.firstIP[7] + r.firstIP[7] += randIPEndWith(255) + if r.firstIP[7] >= tempIP { continue } - tempIP = firstIP[6] - firstIP[6] += randipEndWith(255) - if firstIP[6] >= tempIP { + tempIP = r.firstIP[6] + r.firstIP[6] += randIPEndWith(255) + if r.firstIP[6] >= tempIP { continue } - tempIP = firstIP[5] - firstIP[5] += randipEndWith(255) - if firstIP[5] >= tempIP { + tempIP = r.firstIP[5] + r.firstIP[5] += randIPEndWith(255) + if r.firstIP[5] >= tempIP { continue } - tempIP = firstIP[4] - firstIP[4] += randipEndWith(255) - if firstIP[4] >= tempIP { + tempIP = r.firstIP[4] + r.firstIP[4] += randIPEndWith(255) + if r.firstIP[4] >= tempIP { continue } - tempIP = firstIP[3] - firstIP[3] += randipEndWith(255) - if firstIP[3] >= tempIP { + tempIP = r.firstIP[3] + r.firstIP[3] += randIPEndWith(255) + if r.firstIP[3] >= tempIP { continue } - tempIP = firstIP[2] - firstIP[2] += randipEndWith(255) - if firstIP[2] >= tempIP { + tempIP = r.firstIP[2] + r.firstIP[2] += randIPEndWith(255) + if r.firstIP[2] >= tempIP { continue } - tempIP = firstIP[1] - firstIP[1] += randipEndWith(255) - if firstIP[1] >= tempIP { + tempIP = r.firstIP[1] + r.firstIP[1] += randIPEndWith(255) + if r.firstIP[1] >= tempIP { continue } - tempIP = firstIP[0] - firstIP[0] += randipEndWith(255) + tempIP = r.firstIP[0] + r.firstIP[0] += randIPEndWith(255) } - return } -// 根据子网掩码获取主机数量 -func getCIDRHostNum(mask uint8) (subnetNum int) { - if mask >= 32 { - return 1 +func loadIPRanges() []*net.IPAddr { + if IPFile == "" { + IPFile = defaultInputFile } - - if mask < 32 { - for i := int(32 - mask - 1); i >= 1; i-- { - subnetNum += 1 << i - } - subnetNum += 2 + file, err := os.Open(IPFile) + if err != nil { + log.Fatal(err) } - if subnetNum > 0xFF { - subnetNum = 0xFF + defer file.Close() + ranges := newIPRanges() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + ranges.parseCIDR(scanner.Text()) + if IPv6 { + ranges.chooseIPv6() + continue + } + ranges.chooseIPv4() } - return -} - -// 获取 IP 最后一段最小值和最大值、主机数量 -func getCidrIPRange(cidr string) (minIP, maxIP uint8, ipNum int) { - i := strings.IndexByte(cidr, '/') - addr := cidr[:i] - mask, _ := strconv.ParseUint(cidr[i+1:], 10, 8) - i = strings.LastIndexByte(addr, '.') - seg4, _ := strconv.ParseUint(addr[i+1:], 10, 8) - minIP, maxIP = getIPSegRange(uint8(seg4), uint8(32-mask)) - ipNum = getCIDRHostNum(uint8(mask)) - return -} - -// 根据输入的基础IP地址和CIDR掩码计算一个IP片段的区间 -func getIPSegRange(userSegIP, offset uint8) (uint8, uint8) { - var ipSegMax uint8 = 0xFF - netSegIP := ipSegMax << offset - segMinIP := netSegIP & userSegIP - segMaxIP := userSegIP&(0xFF< Date: Fri, 12 Nov 2021 11:58:21 +0800 Subject: [PATCH 09/22] fix zero result print --- main.go | 13 +++---------- task/tcping.go | 8 ++++++++ utils/csv.go | 4 ++++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index 6830712f..7dba09a5 100644 --- a/main.go +++ b/main.go @@ -96,15 +96,11 @@ https://github.com/XIU2/CloudflareSpeedTest func main() { go checkUpdate() // 检查版本更新 - // 开始延迟测速 fmt.Printf("# XIU2/CloudflareSpeedTest %s \n", version) - ipVersion := "IPv4" - if task.IPv6 { // IPv6 模式判断 - ipVersion = "IPv6" - } - fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%v,平均延迟下限:%v)\n", ipVersion, task.TCPPort, utils.InputMaxDelay, utils.InputMinDelay) + // 开始延迟测速 pingData := task.NewPing().Run().FilterDelay() + // 开始下载测速 speedData := task.TestDownloadSpeed(pingData) utils.ExportCsv(speedData) speedData.Print(task.IPv6) @@ -113,11 +109,8 @@ func main() { fmt.Printf("\n*** 发现新版本 [%s]!请前往 [https://github.com/XIU2/CloudflareSpeedTest] 更新! ***\n", versionNew) } - if utils.Output != "" { - fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", utils.Output) - } if runtime.GOOS == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) - fmt.Printf("按下 回车键 或 Ctrl+C 退出。\n") + fmt.Println("\n按下 回车键 或 Ctrl+C 退出。") var pause int fmt.Scanln(&pause) } diff --git a/task/tcping.go b/task/tcping.go index 054d3602..52d759f8 100644 --- a/task/tcping.go +++ b/task/tcping.go @@ -59,6 +59,14 @@ func NewPing() *Ping { } func (p *Ping) Run() utils.PingDelaySet { + if len(p.ips) == 0 { + return p.csv + } + ipVersion := "IPv4" + if IPv6 { // IPv6 模式判断 + ipVersion = "IPv6" + } + fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%v,平均延迟下限:%v)\n", ipVersion, TCPPort, utils.InputMaxDelay, utils.InputMinDelay) for _, ip := range p.ips { p.wg.Add(1) p.control <- false diff --git a/utils/csv.go b/utils/csv.go index 6240d722..24d9f988 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -59,6 +59,9 @@ func ExportCsv(data []CloudflareIPData) { if Output == "" { Output = defaultOutput } + if len(data) == 0 { + return + } fp, err := os.Create(Output) if err != nil { log.Fatalf("创建文件[%s]失败:%v", Output, err) @@ -69,6 +72,7 @@ func ExportCsv(data []CloudflareIPData) { w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"}) w.WriteAll(convertToString(data)) w.Flush() + fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", Output) } func convertToString(data []CloudflareIPData) [][]string { From 49c14f3e0ed915eac31de6388e2160b90887fafe Mon Sep 17 00:00:00 2001 From: mazhuang Date: Fri, 12 Nov 2021 17:58:13 +0800 Subject: [PATCH 10/22] replace ipv6 repeat code --- task/ip.go | 80 ++++++------------------------------------------------ 1 file changed, 9 insertions(+), 71 deletions(-) diff --git a/task/ip.go b/task/ip.go index eb55937f..d1bdc762 100644 --- a/task/ip.go +++ b/task/ip.go @@ -2,7 +2,6 @@ package task import ( "bufio" - "fmt" "log" "math/rand" "net" @@ -94,7 +93,6 @@ func (r *IPRanges) getIPRange() (minIP, hosts byte) { func (r *IPRanges) chooseIPv4() { minIP, hosts := r.getIPRange() - fmt.Println(minIP, hosts) for r.ipNet.Contains(r.firstIP) { if TestAll { // 如果是测速全部 IP for i := byte(0); i <= hosts; i++ { // 遍历 IP 最后一段最小值到最大值 @@ -122,76 +120,16 @@ func (r *IPRanges) chooseIPv6() { r.firstIP[15] = randIPEndWith(255) // 随机 IP 的最后一段 r.firstIP[14] = randIPEndWith(255) // 随机 IP 的最后一段 } - firstIPCopy := make([]byte, len(r.firstIP)) - copy(firstIPCopy, r.firstIP) - r.appendIP(firstIPCopy) - tempIP = r.firstIP[13] - r.firstIP[13] += randIPEndWith(255) - if r.firstIP[13] >= tempIP { - continue - } - tempIP = r.firstIP[12] - r.firstIP[12] += randIPEndWith(255) - if r.firstIP[12] >= tempIP { - continue - } - tempIP = r.firstIP[11] - r.firstIP[11] += randIPEndWith(255) - if r.firstIP[11] >= tempIP { - continue - } - tempIP = r.firstIP[10] - r.firstIP[10] += randIPEndWith(255) - if r.firstIP[10] >= tempIP { - continue - } - tempIP = r.firstIP[9] - r.firstIP[9] += randIPEndWith(255) - if r.firstIP[9] >= tempIP { - continue - } - tempIP = r.firstIP[8] - r.firstIP[8] += randIPEndWith(255) - if r.firstIP[8] >= tempIP { - continue - } - tempIP = r.firstIP[7] - r.firstIP[7] += randIPEndWith(255) - if r.firstIP[7] >= tempIP { - continue - } - tempIP = r.firstIP[6] - r.firstIP[6] += randIPEndWith(255) - if r.firstIP[6] >= tempIP { - continue - } - tempIP = r.firstIP[5] - r.firstIP[5] += randIPEndWith(255) - if r.firstIP[5] >= tempIP { - continue - } - tempIP = r.firstIP[4] - r.firstIP[4] += randIPEndWith(255) - if r.firstIP[4] >= tempIP { - continue - } - tempIP = r.firstIP[3] - r.firstIP[3] += randIPEndWith(255) - if r.firstIP[3] >= tempIP { - continue - } - tempIP = r.firstIP[2] - r.firstIP[2] += randIPEndWith(255) - if r.firstIP[2] >= tempIP { - continue - } - tempIP = r.firstIP[1] - r.firstIP[1] += randIPEndWith(255) - if r.firstIP[1] >= tempIP { - continue + targetIP := make([]byte, len(r.firstIP)) + copy(targetIP, r.firstIP) + r.appendIP(targetIP) + for i := 13; i >= 0; i-- { + tempIP = r.firstIP[i] + r.firstIP[i] += randIPEndWith(255) + if r.firstIP[i] >= tempIP { + break + } } - tempIP = r.firstIP[0] - r.firstIP[0] += randIPEndWith(255) } } From fdbf9ca1313c82c2d5489e3e561dee788e212954 Mon Sep 17 00:00:00 2001 From: mazhuang Date: Fri, 12 Nov 2021 17:58:37 +0800 Subject: [PATCH 11/22] update download bar num --- task/download.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/task/download.go b/task/download.go index 1c1ab8ee..28d9b452 100644 --- a/task/download.go +++ b/task/download.go @@ -65,14 +65,14 @@ func TestDownloadSpeed(ipSet utils.PingDelaySet) (sppedSet utils.DownloadSpeedSe } fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum) - bar := utils.NewBar(TestCount) + bar := utils.NewBar(testNum) for i := 0; i < testNum; i++ { - speed := downloadSpeedHandler(ipSet[i].IP) + speed := downloadHandler(ipSet[i].IP) ipSet[i].DownloadSpeed = speed + bar.Grow(1) // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 if speed >= MinSpeed*1024*1024 { sppedSet = append(sppedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中 - bar.Grow(1) if len(sppedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 break } @@ -94,8 +94,8 @@ func getDialContext(ip *net.IPAddr) func(ctx context.Context, network, address s } } -//bool : can download,float32 downloadSpeed -func downloadSpeedHandler(ip *net.IPAddr) float64 { +// return download Speed +func downloadHandler(ip *net.IPAddr) float64 { client := &http.Client{ Transport: &http.Transport{DialContext: getDialContext(ip)}, Timeout: Timeout, @@ -136,13 +136,13 @@ func downloadSpeedHandler(ip *net.IPAddr) float64 { break } bufferRead, err := response.Body.Read(buffer) - contentRead += int64(bufferRead) if err != nil { if err != io.EOF { break } e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice))) } + contentRead += int64(bufferRead) } return e.Value() / (Timeout.Seconds() / 120) From ab6390a4a4d8fa45088eb8257ebae17bc28e8fb0 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 16:49:16 +0800 Subject: [PATCH 12/22] change the input time parameter to a number --- main.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index 7dba09a5..5bcc3369 100644 --- a/main.go +++ b/main.go @@ -31,8 +31,8 @@ https://github.com/XIU2/CloudflareSpeedTest 延迟测速次数;单个 IP 延迟测速次数,为 1 时将过滤丢包的IP,TCP协议;(默认 4) -tp 443 延迟测速端口;延迟测速 TCP 协议的端口;(默认 443) - -dn 20 - 下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 20) + -dn 10 + 下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 10) -dt 10 下载测速时间;单个 IP 下载测速最长时间,单位:秒;(默认 10) -url https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png @@ -43,8 +43,8 @@ https://github.com/XIU2/CloudflareSpeedTest 平均延迟下限;只输出高于指定平均延迟的 IP,可与其他上限/下限搭配,过滤被假蔷的 IP;(默认 0 ms) -sl 5 下载速度下限;只输出高于指定下载速度的 IP,凑够指定数量 [-dn] 才会停止测速;(默认 0.00 MB/s) - -p 20 - 显示结果数量;测速后直接显示指定数量的结果,为 0 时不显示结果直接退出;(默认 20) + -p 10 + 显示结果数量;测速后直接显示指定数量的结果,为 0 时不显示结果直接退出;(默认 10) -f ip.txt IP段数据文件;如路径含有空格请加上引号;支持其他 CDN IP段;(默认 ip.txt) -o result.csv @@ -60,13 +60,13 @@ https://github.com/XIU2/CloudflareSpeedTest -h 打印帮助说明 ` - + var minDelay, maxDelay, downloadTime int flag.IntVar(&task.Routines, "n", 200, "测速线程数量") flag.IntVar(&task.PingTimes, "t", 4, "延迟测速次数") flag.IntVar(&task.TCPPort, "tp", 443, "延迟测速端口") - flag.DurationVar(&utils.InputMaxDelay, "tl", 9999*time.Millisecond, "平均延迟上限") - flag.DurationVar(&utils.InputMinDelay, "tll", time.Duration(0), "平均延迟下限") - flag.DurationVar(&task.Timeout, "dt", 10*time.Second, "下载测速时间") + flag.IntVar(&maxDelay, "tl", 9999, "平均延迟上限") + flag.IntVar(&minDelay, "tll", 0, "平均延迟下限") + flag.IntVar(&downloadTime, "dt", 10, "下载测速时间") flag.IntVar(&task.TestCount, "dn", 10, "下载测速数量") flag.StringVar(&task.URL, "url", "https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png", "下载测速地址") flag.BoolVar(&task.Disable, "dd", false, "禁用下载测速") @@ -74,12 +74,16 @@ https://github.com/XIU2/CloudflareSpeedTest flag.BoolVar(&task.TestAll, "allip", false, "测速全部 IP") flag.StringVar(&task.IPFile, "f", "ip.txt", "IP 数据文件") flag.Float64Var(&task.MinSpeed, "sl", 0, "下载速度下限") - flag.IntVar(&utils.PrintNum, "p", 20, "显示结果数量") + flag.IntVar(&utils.PrintNum, "p", 10, "显示结果数量") flag.StringVar(&utils.Output, "o", "result.csv", "输出结果文件") flag.BoolVar(&printVersion, "v", false, "打印程序版本") - flag.Usage = func() { fmt.Print(help) } flag.Parse() + + utils.InputMaxDelay = time.Duration(maxDelay) * time.Millisecond + utils.InputMinDelay = time.Duration(minDelay) * time.Millisecond + task.Timeout = time.Duration(downloadTime) * time.Second + if printVersion { println(version) fmt.Println("检查版本更新中...") @@ -118,7 +122,7 @@ func main() { // 检查更新 func checkUpdate() { - timeout := time.Duration(10 * time.Second) + timeout := 10 * time.Second client := http.Client{Timeout: timeout} res, err := client.Get("https://api.xiuer.pw/ver/cloudflarespeedtest.txt") if err != nil { From 7301d32cbe7548e6cd16a94e480c58875f86b0ec Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 16:49:47 +0800 Subject: [PATCH 13/22] update print format --- README.md | 10 +++++----- task/tcping.go | 2 +- utils/csv.go | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5d9b1091..2171c07d 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ chmod +x CloudflareST ### 结果示例 -测速完毕后,默认会显示**最快的 20 个 IP**,示例(我联通白天测速结果): +测速完毕后,默认会显示**最快的 10 个 IP**,示例(我联通白天测速结果): ``` bash IP 地址 已发送 已接收 丢包率 平均延迟 下载速度 (MB/s) @@ -116,8 +116,8 @@ https://github.com/XIU2/CloudflareSpeedTest 延迟测速次数;单个 IP 延迟测速次数,为 1 时将过滤丢包的IP,TCP协议;(默认 4 ) -tp 443 延迟测速端口;延迟测速 TCP 协议的端口;(默认 443 ) - -dn 20 - 下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 20 ) + -dn 10 + 下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 10 ) -dt 10 下载测速时间;单个 IP 下载测速最长时间,单位:秒;(默认 10 ) -url https://cf.xiu2.xyz/Github/CloudflareSpeedTest.png @@ -128,8 +128,8 @@ https://github.com/XIU2/CloudflareSpeedTest 平均延迟下限;只输出高于指定平均延迟的 IP,可与其他上限/下限搭配,过滤被假蔷的 IP;(默认 0 ms) -sl 5 下载速度下限;只输出高于指定下载速度的 IP,凑够指定数量 [-dn] 才会停止测速;(默认 0.00 MB/s) - -p 20 - 显示结果数量;测速后直接显示指定数量的结果,为 0 时不显示结果直接退出;(默认 20 ) + -p 10 + 显示结果数量;测速后直接显示指定数量的结果,为 0 时不显示结果直接退出;(默认 10 ) -f ip.txt IP段数据文件;如路径含有空格请加上引号;支持其他 CDN IP段;(默认 ip.txt ) -o result.csv diff --git a/task/tcping.go b/task/tcping.go index 52d759f8..69dd6847 100644 --- a/task/tcping.go +++ b/task/tcping.go @@ -66,7 +66,7 @@ func (p *Ping) Run() utils.PingDelaySet { if IPv6 { // IPv6 模式判断 ipVersion = "IPv6" } - fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d ,平均延迟上限:%v,平均延迟下限:%v)\n", ipVersion, TCPPort, utils.InputMaxDelay, utils.InputMinDelay) + fmt.Printf("开始延迟测速(模式:TCP %s,端口:%d,平均延迟上限:%vms,平均延迟下限:%vms)\n", ipVersion, TCPPort, utils.InputMaxDelay.Milliseconds(), utils.InputMinDelay.Milliseconds()) for _, ip := range p.ips { p.wg.Add(1) p.control <- false diff --git a/utils/csv.go b/utils/csv.go index 24d9f988..033c15fd 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -20,7 +20,7 @@ var ( InputMaxDelay = maxDelay InputMinDelay = minDelay Output = defaultOutput - PrintNum = 20 + PrintNum = 10 ) type PingData struct { @@ -50,7 +50,7 @@ func (cf *CloudflareIPData) toString() []string { result[1] = strconv.Itoa(cf.Sended) result[2] = strconv.Itoa(cf.Received) result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32) - result[4] = cf.Delay.String() + result[4] = strconv.FormatFloat(cf.Delay.Seconds()*1000, 'f', 2, 32) result[5] = strconv.FormatFloat(cf.DownloadSpeed/1024/1024, 'f', 2, 32) return result } @@ -72,7 +72,6 @@ func ExportCsv(data []CloudflareIPData) { w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"}) w.WriteAll(convertToString(data)) w.Flush() - fmt.Printf("完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", Output) } func convertToString(data []CloudflareIPData) [][]string { @@ -142,7 +141,7 @@ func (s DownloadSpeedSet) Print(ipv6 bool) { PrintNum = len(dateString) } headFormat := "%-16s%-5s%-5s%-5s%-6s%-11s\n" - dataFormat := "%-18s%-8s%-8s%-8s%-15s%-15s\n" + dataFormat := "%-18s%-8s%-8s%-8s%-10s%-15s\n" if ipv6 { // IPv6 太长了,所以需要调整一下间隔 headFormat = "%-40s%-5s%-5s%-5s%-6s%-11s\n" dataFormat = "%-42s%-8s%-8s%-8s%-10s%-15s\n" @@ -151,4 +150,5 @@ func (s DownloadSpeedSet) Print(ipv6 bool) { for i := 0; i < PrintNum; i++ { fmt.Printf(dataFormat, dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) } + fmt.Printf("\n完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", Output) } From ed0a8bbfea5efcd6cf14a17ef2aeb9a6ebe95906 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 18:19:17 +0800 Subject: [PATCH 14/22] fix allip deadloop bug --- task/ip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task/ip.go b/task/ip.go index d1bdc762..3e76d313 100644 --- a/task/ip.go +++ b/task/ip.go @@ -95,7 +95,7 @@ func (r *IPRanges) chooseIPv4() { minIP, hosts := r.getIPRange() for r.ipNet.Contains(r.firstIP) { if TestAll { // 如果是测速全部 IP - for i := byte(0); i <= hosts; i++ { // 遍历 IP 最后一段最小值到最大值 + for i := byte(0); i < hosts; i++ { // 遍历 IP 最后一段最小值到最大值 r.appendIPv4(i + minIP) } } else { // 随机 IP 的最后一段 0.0.0.X From 2fa023c7f3bdbe0be7704028caa19beac0aac67a Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 18:27:11 +0800 Subject: [PATCH 15/22] fix full ip lost 255 bug --- task/ip.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/task/ip.go b/task/ip.go index 3e76d313..ee5c24f0 100644 --- a/task/ip.go +++ b/task/ip.go @@ -95,8 +95,8 @@ func (r *IPRanges) chooseIPv4() { minIP, hosts := r.getIPRange() for r.ipNet.Contains(r.firstIP) { if TestAll { // 如果是测速全部 IP - for i := byte(0); i < hosts; i++ { // 遍历 IP 最后一段最小值到最大值 - r.appendIPv4(i + minIP) + for i := 0; i <= int(hosts); i++ { // 遍历 IP 最后一段最小值到最大值 + r.appendIPv4(byte(i) + minIP) } } else { // 随机 IP 的最后一段 0.0.0.X r.appendIPv4(minIP + randIPEndWith(hosts)) From f82425bbb6ba41277bb7be33c5de927eb12f0464 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 20:27:36 +0800 Subject: [PATCH 16/22] fix filter delay time invalid bug --- utils/csv.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/csv.go b/utils/csv.go index 033c15fd..263e2631 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -89,10 +89,10 @@ func (s PingDelaySet) FilterDelay() (data PingDelaySet) { return s } for _, v := range s { - if v.Delay > maxDelay { // 平均延迟上限 + if v.Delay > InputMaxDelay { // 平均延迟上限 break } - if v.Delay <= minDelay { // 平均延迟下限 + if v.Delay <= InputMinDelay { // 平均延迟下限 continue } data = append(data, v) // 延迟满足条件时,添加到新数组中 From 8eea8cdd0edaafb49af52ebef425c374371ab878 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 22:20:16 +0800 Subject: [PATCH 17/22] fix filter delay time bug --- utils/csv.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/csv.go b/utils/csv.go index 263e2631..e2960080 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -13,7 +13,7 @@ import ( const ( defaultOutput = "result.csv" maxDelay = 9999 * time.Millisecond - minDelay = time.Duration(0) + minDelay = 0 * time.Millisecond ) var ( @@ -85,14 +85,14 @@ func convertToString(data []CloudflareIPData) [][]string { type PingDelaySet []CloudflareIPData func (s PingDelaySet) FilterDelay() (data PingDelaySet) { - if InputMaxDelay >= maxDelay || InputMinDelay <= minDelay { + if InputMaxDelay > maxDelay || InputMinDelay < minDelay { return s } for _, v := range s { if v.Delay > InputMaxDelay { // 平均延迟上限 break } - if v.Delay <= InputMinDelay { // 平均延迟下限 + if v.Delay < InputMinDelay { // 平均延迟下限 continue } data = append(data, v) // 延迟满足条件时,添加到新数组中 From 2c46cfcd0fc6513e1eef036eea653b2c612fb2de Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sat, 13 Nov 2021 22:57:18 +0800 Subject: [PATCH 18/22] the speed progress bar shows test count --- main.go | 6 ++++++ task/download.go | 15 +++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 5bcc3369..267c91de 100644 --- a/main.go +++ b/main.go @@ -80,6 +80,9 @@ https://github.com/XIU2/CloudflareSpeedTest flag.Usage = func() { fmt.Print(help) } flag.Parse() + if task.MinSpeed > 0 && time.Duration(maxDelay)*time.Millisecond == utils.InputMaxDelay { + fmt.Println("[警告] '-sl' 参数建议和 '-tl' 参数一起使用") + } utils.InputMaxDelay = time.Duration(maxDelay) * time.Millisecond utils.InputMinDelay = time.Duration(minDelay) * time.Millisecond task.Timeout = time.Duration(downloadTime) * time.Second @@ -112,7 +115,10 @@ func main() { if versionNew != "" { fmt.Printf("\n*** 发现新版本 [%s]!请前往 [https://github.com/XIU2/CloudflareSpeedTest] 更新! ***\n", versionNew) } + endPrint() +} +func endPrint() { if runtime.GOOS == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) fmt.Println("\n按下 回车键 或 Ctrl+C 退出。") var pause int diff --git a/task/download.go b/task/download.go index 28d9b452..a16a4bd2 100644 --- a/task/download.go +++ b/task/download.go @@ -50,7 +50,7 @@ func checkDownloadDefault() { } } -func TestDownloadSpeed(ipSet utils.PingDelaySet) (sppedSet utils.DownloadSpeedSet) { +func TestDownloadSpeed(ipSet utils.PingDelaySet) (speedSet utils.DownloadSpeedSet) { checkDownloadDefault() if Disable { return utils.DownloadSpeedSet(ipSet) @@ -65,22 +65,25 @@ func TestDownloadSpeed(ipSet utils.PingDelaySet) (sppedSet utils.DownloadSpeedSe } fmt.Printf("开始下载测速(下载速度下限:%.2f MB/s,下载测速数量:%d,下载测速队列:%d):\n", MinSpeed, TestCount, testNum) - bar := utils.NewBar(testNum) + bar := utils.NewBar(TestCount) for i := 0; i < testNum; i++ { speed := downloadHandler(ipSet[i].IP) ipSet[i].DownloadSpeed = speed - bar.Grow(1) // 在每个 IP 下载测速后,以 [下载速度下限] 条件过滤结果 if speed >= MinSpeed*1024*1024 { - sppedSet = append(sppedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中 - if len(sppedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 + bar.Grow(1) + speedSet = append(speedSet, ipSet[i]) // 高于下载速度下限时,添加到新数组中 + if len(speedSet) == TestCount { // 凑够满足条件的 IP 时(下载测速数量 -dn),就跳出循环 break } } } bar.Done() + if len(speedSet) == 0 { // 没有符合速度限制的数据,返回所有测试数据 + speedSet = utils.DownloadSpeedSet(ipSet) + } // 按速度排序 - sort.Sort(sppedSet) + sort.Sort(speedSet) return } From 272eb40d5b43538039db75e25bb5aa25df5972dd Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sun, 14 Nov 2021 12:47:57 +0800 Subject: [PATCH 19/22] fix `-p=0` don't print result bug --- main.go | 3 +++ utils/csv.go | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/main.go b/main.go index 267c91de..4ea48dfb 100644 --- a/main.go +++ b/main.go @@ -119,6 +119,9 @@ func main() { } func endPrint() { + if utils.NoPrintResult() { + return + } if runtime.GOOS == "windows" { // 如果是 Windows 系统,则需要按下 回车键 或 Ctrl+C 退出(避免通过双击运行时,测速完毕后直接关闭) fmt.Println("\n按下 回车键 或 Ctrl+C 退出。") var pause int diff --git a/utils/csv.go b/utils/csv.go index e2960080..2928be3d 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -23,6 +23,10 @@ var ( PrintNum = 10 ) +func NoPrintResult() bool { + return PrintNum == 0 +} + type PingData struct { IP *net.IPAddr Sended int @@ -132,6 +136,9 @@ func (s DownloadSpeedSet) Swap(i, j int) { } func (s DownloadSpeedSet) Print(ipv6 bool) { + if NoPrintResult() { + return + } if len(s) <= 0 { // IP数组长度(IP数量) 大于 0 时继续 fmt.Println("\n[信息] 完整测速结果 IP 数量为 0,跳过输出结果。") return From 115bd2af0358ae287984bad5cc53ebe53e363d53 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sun, 14 Nov 2021 12:59:46 +0800 Subject: [PATCH 20/22] fix `-o=""/" "` don't write to file --- utils/csv.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/utils/csv.go b/utils/csv.go index 2928be3d..42a8f8d3 100644 --- a/utils/csv.go +++ b/utils/csv.go @@ -23,10 +23,16 @@ var ( PrintNum = 10 ) +// 是否打印测试结果 func NoPrintResult() bool { return PrintNum == 0 } +// 是否输出到文件 +func noOutput() bool { + return Output == "" || Output == " " +} + type PingData struct { IP *net.IPAddr Sended int @@ -60,10 +66,7 @@ func (cf *CloudflareIPData) toString() []string { } func ExportCsv(data []CloudflareIPData) { - if Output == "" { - Output = defaultOutput - } - if len(data) == 0 { + if noOutput() || len(data) == 0 { return } fp, err := os.Create(Output) @@ -73,8 +76,8 @@ func ExportCsv(data []CloudflareIPData) { } defer fp.Close() w := csv.NewWriter(fp) //创建一个新的写入文件流 - w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"}) - w.WriteAll(convertToString(data)) + _ = w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"}) + _ = w.WriteAll(convertToString(data)) w.Flush() } @@ -157,5 +160,7 @@ func (s DownloadSpeedSet) Print(ipv6 bool) { for i := 0; i < PrintNum; i++ { fmt.Printf(dataFormat, dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5]) } - fmt.Printf("\n完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", Output) + if !noOutput() { + fmt.Printf("\n完整测速结果已写入 %v 文件,请使用记事本/表格软件查看。\n", Output) + } } From cfe30c2f6af754538f4d0bd0c472b9026a20cbf8 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sun, 14 Nov 2021 14:04:31 +0800 Subject: [PATCH 21/22] fix ipv4 last segment = 0 bug --- task/ip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task/ip.go b/task/ip.go index ee5c24f0..14ac6bbc 100644 --- a/task/ip.go +++ b/task/ip.go @@ -116,7 +116,7 @@ func (r *IPRanges) chooseIPv6() { for r.ipNet.Contains(r.firstIP) { //fmt.Println(firstIP) //fmt.Println(firstIP[0], firstIP[1], firstIP[2], firstIP[3], firstIP[4], firstIP[5], firstIP[6], firstIP[7], firstIP[8], firstIP[9], firstIP[10], firstIP[11], firstIP[12], firstIP[13], firstIP[14], firstIP[15]) - if r.mask == "/128" { + if r.mask != "/128" { r.firstIP[15] = randIPEndWith(255) // 随机 IP 的最后一段 r.firstIP[14] = randIPEndWith(255) // 随机 IP 的最后一段 } From f6288f4e5266c7a47f9ac3b52d6f37a3724be6b8 Mon Sep 17 00:00:00 2001 From: mz <2392368224@qq.com> Date: Sun, 14 Nov 2021 14:10:44 +0800 Subject: [PATCH 22/22] tcphandler just test one ip --- task/tcping.go | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/task/tcping.go b/task/tcping.go index 69dd6847..fc5f9de9 100644 --- a/task/tcping.go +++ b/task/tcping.go @@ -120,43 +120,18 @@ func (p *Ping) appendIPData(data *utils.PingData) { }) } -//return Success packetRecv averagePingTime specificIPAddr +// handle tcping func (p *Ping) tcpingHandler(ip *net.IPAddr) { - ipCanConnect := false - pingRecv := 0 - var delay time.Duration - for !ipCanConnect { - recv, totalDlay := p.checkConnection(ip) - if recv > 0 { - ipCanConnect = true - pingRecv = recv - delay = totalDlay - } else { - ip.IP[15]++ - if ip.IP[15] == 0 { - break - } - break - } - } + recv, totalDlay := p.checkConnection(ip) p.bar.Grow(1) - if !ipCanConnect { + if recv == 0 { return } - // for i := 0; i < PingTimes; i++ { - // pingSuccess, pingTimeCurrent := p.tcping(ip) - // progressHandler(utils.NormalPing) - // if pingSuccess { - // pingRecv++ - // pingTime += pingTimeCurrent - // } - // } data := &utils.PingData{ IP: ip, Sended: PingTimes, - Received: pingRecv, - Delay: delay / time.Duration(pingRecv), + Received: recv, + Delay: totalDlay / time.Duration(recv), } p.appendIPData(data) - return }