4 Commits

Author SHA1 Message Date
xiu2
4c92eae311 不输出结果文件 -o "" 改为 -o " " 2020-09-05 17:47:03 +08:00
xiu2
efdbc8f08e 优化直接输出结果排版;成功比率改为丢包率 2020-09-04 15:43:16 +08:00
xiu2
e85a03c651 新增 自定义TCP端口 功能等 2020-09-03 20:07:15 +08:00
xiu2
5d00d7c5ff 新增 自定义TCP端口 功能。 2020-09-03 19:36:09 +08:00
4 changed files with 59 additions and 38 deletions

View File

@@ -18,10 +18,10 @@
1. 下载编译好的可执行文件 [蓝奏云](https://www.lanzoux.com/b0742hkxe) / [Github](https://github.com/XIU2/CloudflareSpeedTest/releases) 并解压。 1. 下载编译好的可执行文件 [蓝奏云](https://www.lanzoux.com/b0742hkxe) / [Github](https://github.com/XIU2/CloudflareSpeedTest/releases) 并解压。
2. 双击运行 `CloudflareST.exe`文件Windows系统等待测速... 2. 双击运行 `CloudflareST.exe`文件Windows系统等待测速...
测速完毕后,会结果保存在当前目录下的 `result.csv` 文件中,用记事本打开,排序为**延迟由低到高**,每一列用逗号分隔,分别是: 测速完毕后,会显示最快的 20 个 IP完整结果保存在当前目录下的 `result.csv` 文件中,用记事本打开,排序为**延迟由低到高**,每一列用逗号分隔,分别是:
``` ```
IP 地址, 测试次数, 成功次数, 成功比率, 平均延迟, 下载速度 (MB/s) IP 地址, 已发送, 已接收, 丢包率, 平均延迟, 下载速度 (MB/s)
104.27.70.18, 4, 4, 1.00, 150.79, 12.89 104.27.70.18, 4, 4, 0.00, 150.79, 12.89
``` ```
选择一个平均延迟与下载速度都不错的 IP 放到 `Hosts` 文件中(指向域名)。 选择一个平均延迟与下载速度都不错的 IP 放到 `Hosts` 文件中(指向域名)。
@@ -41,6 +41,8 @@ https://github.com/XIU2/CloudflareSpeedTest
测速线程数量;数值越大速度越快,请勿超过 1000(结果误差大)(默认 500) 测速线程数量;数值越大速度越快,请勿超过 1000(结果误差大)(默认 500)
-t 4 -t 4
延迟测速次数;单个 IP 测速次数,为 1 时将过滤丢包的IPTCP协议(默认 4) 延迟测速次数;单个 IP 测速次数,为 1 时将过滤丢包的IPTCP协议(默认 4)
-tp 443
延迟测速端口;延迟测速 TCP 协议的端口;(默认 443)
-dn 20 -dn 20
下载测速数量;延迟测速并排序后,从最低延迟起下载测速数量,请勿太多(速度慢)(默认 20) 下载测速数量;延迟测速并排序后,从最低延迟起下载测速数量,请勿太多(速度慢)(默认 20)
-dt 10 -dt 10
@@ -50,7 +52,7 @@ https://github.com/XIU2/CloudflareSpeedTest
-f ip.txt -f ip.txt
IP 数据文件;相对/绝对路径,如包含空格请加上引号;支持其他 CDN IP段记得禁用下载测速(默认 ip.txt) IP 数据文件;相对/绝对路径,如包含空格请加上引号;支持其他 CDN IP段记得禁用下载测速(默认 ip.txt)
-o result.csv -o result.csv
输出结果文件;相对/绝对路径,如包含空格请加上引号;允许 .txt 等后缀;(默认 result.csv) 输出结果文件;相对/绝对路径,如包含空格请加上引号;为空格时不输出结果文件( -o " " );允许其他后缀;(默认 result.csv)
-dd -dd
禁用下载测速;如果带上该参数就是禁用下载测速;(默认 启用) 禁用下载测速;如果带上该参数就是禁用下载测速;(默认 启用)
-v -v
@@ -59,9 +61,10 @@ https://github.com/XIU2/CloudflareSpeedTest
打印帮助说明 打印帮助说明
示例: 示例:
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p -1 -f "ip.txt" -o "result.csv" -dd CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 -f "ip.txt" -o "" -dd
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p -1 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "ip.txt" -o "result.csv" -dd
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd
``` ```
#### 使用示例 #### 使用示例
@@ -71,19 +74,22 @@ https://github.com/XIU2/CloudflareSpeedTest
``` cmd ``` cmd
# CMD 示例 # CMD 示例
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10
# 指定 IP数据文件不输出结果文件直接显示结果-p 20 条)
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 -f "ip.txt" -o " " -dd
# 指定 IP数据文件 及 输出结果文件(相对路径,即当前目录下) # 指定 IP数据文件 及 输出结果文件(相对路径,即当前目录下)
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p -1 -f "ip.txt" -o "result.csv" -dd CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "ip.txt" -o "result.csv" -dd
# 指定 IP数据文件 及 输出结果文件(绝对路径,即 C:\abc\ 目录下) # 指定 IP数据文件 及 输出结果文件(绝对路径,即 C:\abc\ 目录下)
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p -1 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd
``` ```
``` cmd ``` cmd
# 快捷方式示例(右键快捷方式 - 目标) # 快捷方式示例(右键快捷方式 - 目标)
## 如果有引号就放在引号外面,记得引号和 - 之间有空格。 ## 如果有引号就放在引号外面,记得引号和 - 之间有空格。
"D:\Program Files\CloudflareST\CloudflareST.exe" -n 500 -t 4 -dn 20 -dt 10 -p 20 "D:\Program Files\CloudflareST\CloudflareST.exe" -n 500 -t 4 -dn 20 -dt 10
``` ```
**** ****

42
main.go
View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"sort" "sort"
"strconv"
"sync" "sync"
"time" "time"
@@ -13,6 +14,7 @@ import (
var version string var version string
var disableDownload bool var disableDownload bool
var tcpPort int
var ipFile string var ipFile string
var outputFile string var outputFile string
var printResult int var printResult int
@@ -30,6 +32,8 @@ https://github.com/XIU2/CloudflareSpeedTest
测速线程数量;数值越大速度越快,请勿超过 1000(结果误差大)(默认 500) 测速线程数量;数值越大速度越快,请勿超过 1000(结果误差大)(默认 500)
-t 4 -t 4
延迟测速次数;单个 IP 测速次数,为 1 时将过滤丢包的IPTCP协议(默认 4) 延迟测速次数;单个 IP 测速次数,为 1 时将过滤丢包的IPTCP协议(默认 4)
-tp 443
延迟测速端口;延迟测速 TCP 协议的端口;(默认 443)
-dn 20 -dn 20
下载测速数量;延迟测速并排序后,从最低延迟起下载测速数量,请勿太多(速度慢)(默认 20) 下载测速数量;延迟测速并排序后,从最低延迟起下载测速数量,请勿太多(速度慢)(默认 20)
-dt 10 -dt 10
@@ -39,7 +43,7 @@ https://github.com/XIU2/CloudflareSpeedTest
-f ip.txt -f ip.txt
IP 数据文件;相对/绝对路径,如包含空格请加上引号;支持其他 CDN IP段记得禁用下载测速(默认 ip.txt) IP 数据文件;相对/绝对路径,如包含空格请加上引号;支持其他 CDN IP段记得禁用下载测速(默认 ip.txt)
-o result.csv -o result.csv
输出结果文件;相对/绝对路径,如包含空格请加上引号;允许 .txt 等后缀;(默认 result.csv) 输出结果文件;相对/绝对路径,如包含空格请加上引号;为空格时不输出结果文件( -o " " );允许其他后缀;(默认 result.csv)
-dd -dd
禁用下载测速;如果带上该参数就是禁用下载测速;(默认 启用) 禁用下载测速;如果带上该参数就是禁用下载测速;(默认 启用)
-v -v
@@ -48,12 +52,14 @@ https://github.com/XIU2/CloudflareSpeedTest
打印帮助说明 打印帮助说明
示例: 示例:
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p -1 -f "ip.txt" -o "result.csv" -dd CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 -f "ip.txt" -o " " -dd
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p -1 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd` CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "ip.txt" -o "result.csv" -dd
CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd`
flag.IntVar(&pingRoutine, "n", 500, "测速线程数量") flag.IntVar(&pingRoutine, "n", 500, "测速线程数量")
flag.IntVar(&pingTime, "t", 4, "延迟测速次数") flag.IntVar(&pingTime, "t", 4, "延迟测速次数")
flag.IntVar(&tcpPort, "tp", 443, "延迟测速端口")
flag.IntVar(&downloadTestCount, "dn", 20, "下载测速数量") flag.IntVar(&downloadTestCount, "dn", 20, "下载测速数量")
flag.Int64Var(&downloadSecond, "dt", 10, "下载测速时间") flag.Int64Var(&downloadSecond, "dt", 10, "下载测速时间")
flag.IntVar(&printResult, "p", 20, "直接显示结果") flag.IntVar(&printResult, "p", 20, "直接显示结果")
@@ -76,6 +82,9 @@ https://github.com/XIU2/CloudflareSpeedTest
if pingTime <= 0 { if pingTime <= 0 {
pingTime = 4 pingTime = 4
} }
if tcpPort < 1 || tcpPort > 65535 {
tcpPort = 443
}
if downloadTestCount <= 0 { if downloadTestCount <= 0 {
downloadTestCount = 20 downloadTestCount = 20
} }
@@ -88,8 +97,8 @@ https://github.com/XIU2/CloudflareSpeedTest
if ipFile == "" { if ipFile == "" {
ipFile = "ip.txt" ipFile = "ip.txt"
} }
if outputFile == "" { if outputFile == " " {
outputFile = "result.csv" outputFile = ""
} }
} }
@@ -103,13 +112,13 @@ func main() {
var mu sync.Mutex var mu sync.Mutex
var data = make([]CloudflareIPData, 0) var data = make([]CloudflareIPData, 0)
fmt.Println("开始延迟测速(TCP)") fmt.Println("开始延迟测速模式TCP端口" + strconv.Itoa(tcpPort) + "")
control := make(chan bool, pingRoutine) control := make(chan bool, pingRoutine)
for _, ip := range ips { for _, ip := range ips {
wg.Add(1) wg.Add(1)
control <- false control <- false
handleProgress := handleProgressGenerator(bar) // 多线程进度条 handleProgress := handleProgressGenerator(bar) // 多线程进度条
go tcpingGoroutine(&wg, &mu, ip, pingTime, &data, control, handleProgress) go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress)
} }
wg.Wait() wg.Wait()
bar.Finish() bar.Finish()
@@ -136,6 +145,10 @@ func main() {
} }
} }
if outputFile != "" {
ExportCsv(outputFile, data) // 输出结果到文件
}
// 直接输出结果 // 直接输出结果
if printResult > 0 { // 如果禁用下载测速就跳过 if printResult > 0 { // 如果禁用下载测速就跳过
dateString := convertToString(data) // 转为多维数组 [][]String dateString := convertToString(data) // 转为多维数组 [][]String
@@ -144,18 +157,19 @@ func main() {
printResult = len(dateString) printResult = len(dateString)
fmt.Println("\n[信息] IP数量小于显示结果数量显示结果数量改为IP数量。\n") fmt.Println("\n[信息] IP数量小于显示结果数量显示结果数量改为IP数量。\n")
} }
fmt.Println("\nIP 地址 \t", "测试次数\t", "成功次数\t", "成功比率\t", "平均延迟\t", "下载速度 (MB/s)") fmt.Printf("%-16s%-5s%-5s%-5s%-6s%-11s\n", "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)")
for i := 0; i < printResult; i++ { for i := 0; i < printResult; i++ {
fmt.Println(dateString[i][0], "\t", dateString[i][1], "\t\t", dateString[i][2], "\t\t", dateString[i][3], "\t\t", dateString[i][4], "\t", dateString[i][5]) fmt.Printf("%-18s%-8s%-8s%-8s%-10s%-15s\n", dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5])
}
if outputFile != "" {
fmt.Printf("\n完整内容请查看 %v 文件。请按 回车键 或 Ctrl+C 退出。", outputFile)
} else {
fmt.Printf("\n请按 回车键 或 Ctrl+C 退出。")
} }
fmt.Printf("\n完整内容请查看 %v 文件。请按 回车键 或 Ctrl+C 退出。", outputFile)
var pause int var pause int
fmt.Scanln(&pause) fmt.Scanln(&pause)
} else { } else {
fmt.Println("\n[信息] IP数量为 0跳过输出结果。") fmt.Println("\n[信息] IP数量为 0跳过输出结果。")
} }
} }
// 输出结果到文件
ExportCsv(outputFile, data)
} }

View File

@@ -13,9 +13,9 @@ import (
) )
//bool connectionSucceed float32 time //bool connectionSucceed float32 time
func tcping(ip net.IPAddr) (bool, float32) { func tcping(ip net.IPAddr, tcpPort int) (bool, float32) {
startTime := time.Now() startTime := time.Now()
conn, err := net.DialTimeout("tcp", ip.String()+":"+strconv.Itoa(defaultTcpPort), tcpConnectTimeout) conn, err := net.DialTimeout("tcp", ip.String()+":"+strconv.Itoa(tcpPort), tcpConnectTimeout)
if err != nil { if err != nil {
return false, 0 return false, 0
} else { } else {
@@ -27,11 +27,11 @@ func tcping(ip net.IPAddr) (bool, float32) {
} }
//pingReceived pingTotalTime //pingReceived pingTotalTime
func checkConnection(ip net.IPAddr) (int, float32) { func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) {
pingRecv := 0 pingRecv := 0
var pingTime float32 = 0.0 var pingTime float32 = 0.0
for i := 1; i <= failTime; i++ { for i := 1; i <= failTime; i++ {
pingSucceed, pingTimeCurrent := tcping(ip) pingSucceed, pingTimeCurrent := tcping(ip, tcpPort)
if pingSucceed { if pingSucceed {
pingRecv++ pingRecv++
pingTime += pingTimeCurrent pingTime += pingTimeCurrent
@@ -41,12 +41,12 @@ func checkConnection(ip net.IPAddr) (int, float32) {
} }
//return Success packetRecv averagePingTime specificIPAddr //return Success packetRecv averagePingTime specificIPAddr
func tcpingHandler(ip net.IPAddr, pingCount int, progressHandler func(e progressEvent)) (bool, int, float32, net.IPAddr) { func tcpingHandler(ip net.IPAddr, tcpPort int, pingCount int, progressHandler func(e progressEvent)) (bool, int, float32, net.IPAddr) {
ipCanConnect := false ipCanConnect := false
pingRecv := 0 pingRecv := 0
var pingTime float32 = 0.0 var pingTime float32 = 0.0
for !ipCanConnect { for !ipCanConnect {
pingRecvCurrent, pingTimeCurrent := checkConnection(ip) pingRecvCurrent, pingTimeCurrent := checkConnection(ip, tcpPort)
if pingRecvCurrent != 0 { if pingRecvCurrent != 0 {
ipCanConnect = true ipCanConnect = true
pingRecv = pingRecvCurrent pingRecv = pingRecvCurrent
@@ -62,7 +62,7 @@ func tcpingHandler(ip net.IPAddr, pingCount int, progressHandler func(e progress
if ipCanConnect { if ipCanConnect {
progressHandler(AvailableIPFound) progressHandler(AvailableIPFound)
for i := failTime; i < pingCount; i++ { for i := failTime; i < pingCount; i++ {
pingSuccess, pingTimeCurrent := tcping(ip) pingSuccess, pingTimeCurrent := tcping(ip, tcpPort)
progressHandler(NormalPing) progressHandler(NormalPing)
if pingSuccess { if pingSuccess {
pingRecv++ pingRecv++
@@ -76,9 +76,9 @@ func tcpingHandler(ip net.IPAddr, pingCount int, progressHandler func(e progress
} }
} }
func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, pingCount int, csv *[]CloudflareIPData, control chan bool, progressHandler func(e progressEvent)) { 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() defer wg.Done()
success, pingRecv, pingTimeAvg, currentIP := tcpingHandler(ip, pingCount, progressHandler) success, pingRecv, pingTimeAvg, currentIP := tcpingHandler(ip, tcpPort, pingCount, progressHandler)
if success { if success {
mutex.Lock() mutex.Lock()
var cfdata CloudflareIPData var cfdata CloudflareIPData

View File

@@ -23,7 +23,8 @@ type CloudflareIPData struct {
func (cf *CloudflareIPData) getRecvRate() float32 { func (cf *CloudflareIPData) getRecvRate() float32 {
if cf.recvRate == 0 { if cf.recvRate == 0 {
cf.recvRate = float32(cf.pingReceived) / float32(cf.pingCount) pingLost := cf.pingCount - cf.pingReceived
cf.recvRate = float32(pingLost) / float32(cf.pingCount)
} }
return cf.recvRate return cf.recvRate
} }
@@ -36,7 +37,7 @@ func ExportCsv(filePath string, data []CloudflareIPData) {
} }
defer fp.Close() defer fp.Close()
w := csv.NewWriter(fp) //创建一个新的写入文件流 w := csv.NewWriter(fp) //创建一个新的写入文件流
w.Write([]string{"IP 地址", "测试次数", "成功次数", "成功比率", "平均延迟", "下载速度 (MB/s)"}) w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"})
w.WriteAll(convertToString(data)) w.WriteAll(convertToString(data))
w.Flush() w.Flush()
} }
@@ -81,7 +82,7 @@ const downloadBufferSize = 1024
var downloadTestCount int var downloadTestCount int
const defaultTcpPort = 443 //const defaultTcpPort = 443
const tcpConnectTimeout = time.Second * 1 const tcpConnectTimeout = time.Second * 1
var failTime int var failTime int
@@ -112,7 +113,7 @@ func (cfs CloudflareIPDataSet) Len() int {
func (cfs CloudflareIPDataSet) Less(i, j int) bool { func (cfs CloudflareIPDataSet) Less(i, j int) bool {
if (cfs)[i].getRecvRate() != cfs[j].getRecvRate() { if (cfs)[i].getRecvRate() != cfs[j].getRecvRate() {
return cfs[i].getRecvRate() > cfs[j].getRecvRate() return cfs[i].getRecvRate() < cfs[j].getRecvRate()
} }
return cfs[i].pingTime < cfs[j].pingTime return cfs[i].pingTime < cfs[j].pingTime
} }