main.go 6.0 KB

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