main.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "sort"
  7. "strconv"
  8. "sync"
  9. "time"
  10. "github.com/cheggaaa/pb/v3"
  11. )
  12. var version string
  13. var disableDownload bool
  14. var tcpPort int
  15. var ipFile string
  16. var outputFile string
  17. var printResult int
  18. func init() {
  19. var downloadSecond int64
  20. var printVersion bool
  21. const help = `
  22. CloudflareSpeedTest
  23. 测试 Cloudflare CDN 所有 IP 的延迟和速度,获取最快 IP!
  24. https://github.com/XIU2/CloudflareSpeedTest
  25. 参数:
  26. -n 500
  27. 测速线程数量;数值越大速度越快,请勿超过 1000(结果误差大);(默认 500)
  28. -t 4
  29. 延迟测速次数;单个 IP 测速次数,为 1 时将过滤丢包的IP,TCP协议;(默认 4)
  30. -tp 443
  31. 延迟测速端口;延迟测速 TCP 协议的端口;(默认 443)
  32. -dn 20
  33. 下载测速数量;延迟测速并排序后,从最低延迟起下载测速数量,请勿太多(速度慢);(默认 20)
  34. -dt 10
  35. 下载测速时间;单个 IP 测速最长时间,单位:秒;(默认 10)
  36. -p 20
  37. 直接显示结果;测速后直接显示指定数量的结果,为 -1 时不显示结果直接退出;(默认 20)
  38. -f ip.txt
  39. IP 数据文件;相对/绝对路径,如包含空格请加上引号;支持其他 CDN IP段,记得禁用下载测速;(默认 ip.txt)
  40. -o result.csv
  41. 输出结果文件;相对/绝对路径,如包含空格请加上引号;为空格时不输出结果文件( -o " " );允许其他后缀;(默认 result.csv)
  42. -dd
  43. 禁用下载测速;如果带上该参数就是禁用下载测速;(默认 启用)
  44. -v
  45. 打印程序版本
  46. -h
  47. 打印帮助说明
  48. 示例:
  49. CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10
  50. CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -p 20 -f "ip.txt" -o " " -dd
  51. CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "ip.txt" -o "result.csv" -dd
  52. CloudflareST.exe -n 500 -t 4 -dn 20 -dt 10 -f "C:\abc\ip.txt" -o "C:\abc\result.csv" -dd`
  53. flag.IntVar(&pingRoutine, "n", 500, "测速线程数量")
  54. flag.IntVar(&pingTime, "t", 4, "延迟测速次数")
  55. flag.IntVar(&tcpPort, "tp", 443, "延迟测速端口")
  56. flag.IntVar(&downloadTestCount, "dn", 20, "下载测速数量")
  57. flag.Int64Var(&downloadSecond, "dt", 10, "下载测速时间")
  58. flag.IntVar(&printResult, "p", 20, "直接显示结果")
  59. flag.BoolVar(&disableDownload, "dd", false, "禁用下载测速")
  60. flag.StringVar(&ipFile, "f", "ip.txt", "IP 数据文件")
  61. flag.StringVar(&outputFile, "o", "result.csv", "输出结果文件")
  62. flag.BoolVar(&printVersion, "v", false, "打印程序版本")
  63. downloadTestTime = time.Duration(downloadSecond) * time.Second
  64. flag.Usage = func() { fmt.Print(help) }
  65. flag.Parse()
  66. if printVersion {
  67. println(version)
  68. os.Exit(0)
  69. }
  70. if pingRoutine <= 0 {
  71. pingRoutine = 500
  72. }
  73. if pingTime <= 0 {
  74. pingTime = 4
  75. }
  76. if tcpPort < 1 || tcpPort > 65535 {
  77. tcpPort = 443
  78. }
  79. if downloadTestCount <= 0 {
  80. downloadTestCount = 20
  81. }
  82. if downloadSecond <= 0 {
  83. downloadSecond = 10
  84. }
  85. if printResult == 0 {
  86. printResult = 20
  87. }
  88. if ipFile == "" {
  89. ipFile = "ip.txt"
  90. }
  91. if outputFile == " " {
  92. outputFile = ""
  93. }
  94. }
  95. func main() {
  96. initipEndWith() // 随机数
  97. failTime = pingTime // 设置接收次数
  98. ips := loadFirstIPOfRangeFromFile(ipFile) // 读入IP
  99. pingCount := len(ips) * pingTime // 计算进度条总数(IP*测试次数)
  100. bar := pb.Full.Start(pingCount) // 进度条总数
  101. var wg sync.WaitGroup
  102. var mu sync.Mutex
  103. var data = make([]CloudflareIPData, 0)
  104. fmt.Println("开始延迟测速(模式:TCP,端口:" + strconv.Itoa(tcpPort) + "):")
  105. control := make(chan bool, pingRoutine)
  106. for _, ip := range ips {
  107. wg.Add(1)
  108. control <- false
  109. handleProgress := handleProgressGenerator(bar) // 多线程进度条
  110. go tcpingGoroutine(&wg, &mu, ip, tcpPort, pingTime, &data, control, handleProgress)
  111. }
  112. wg.Wait()
  113. bar.Finish()
  114. sort.Sort(CloudflareIPDataSet(data)) // 排序
  115. // 下载测速
  116. if !disableDownload { // 如果禁用下载测速就跳过
  117. if len(data) > 0 { // IP数组长度(IP数量) 大于 0 时继续
  118. if len(data) < downloadTestCount { // 如果IP数组长度(IP数量) 小于 下载测速次数,则次数改为IP数
  119. downloadTestCount = len(data)
  120. fmt.Println("\n[信息] IP数量小于下载测速次数,下载测速次数改为IP数。\n")
  121. }
  122. bar = pb.Simple.Start(downloadTestCount)
  123. fmt.Println("开始下载测速:")
  124. for i := 0; i < downloadTestCount; i++ {
  125. _, speed := DownloadSpeedHandler(data[i].ip)
  126. data[i].downloadSpeed = speed
  127. bar.Add(1)
  128. }
  129. bar.Finish()
  130. } else {
  131. fmt.Println("\n[信息] IP数量为 0,跳过下载测速。")
  132. }
  133. }
  134. if outputFile != "" {
  135. ExportCsv(outputFile, data) // 输出结果到文件
  136. }
  137. // 直接输出结果
  138. if printResult > 0 { // 如果禁用下载测速就跳过
  139. dateString := convertToString(data) // 转为多维数组 [][]String
  140. if len(dateString) > 0 { // IP数组长度(IP数量) 大于 0 时继续
  141. if len(dateString) < printResult { // 如果IP数组长度(IP数量) 小于 打印次数,则次数改为IP数量
  142. printResult = len(dateString)
  143. fmt.Println("\n[信息] IP数量小于显示结果数量,显示结果数量改为IP数量。\n")
  144. }
  145. fmt.Printf("%-16s%-5s%-5s%-5s%-6s%-11s\n", "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)")
  146. for i := 0; i < printResult; i++ {
  147. 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])
  148. }
  149. if outputFile != "" {
  150. fmt.Printf("\n完整内容请查看 %v 文件。请按 回车键 或 Ctrl+C 退出。", outputFile)
  151. } else {
  152. fmt.Printf("\n请按 回车键 或 Ctrl+C 退出。")
  153. }
  154. var pause int
  155. fmt.Scanln(&pause)
  156. } else {
  157. fmt.Println("\n[信息] IP数量为 0,跳过输出结果。")
  158. }
  159. }
  160. }