123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- package utils
- import (
- "encoding/csv"
- "fmt"
- "log"
- "net"
- "os"
- "strconv"
- "time"
- )
- const (
- defaultOutput = "result.csv"
- maxDelay = 9999 * time.Millisecond
- minDelay = 0 * time.Millisecond
- maxLossRate float32 = 1.0
- )
- var (
- InputMaxDelay = maxDelay
- InputMinDelay = minDelay
- InputMaxLossRate = maxLossRate
- Output = defaultOutput
- PrintNum = 10
- Debug = false // 是否开启调试模式
- )
- // 是否打印测试结果
- func NoPrintResult() bool {
- return PrintNum == 0
- }
- // 是否输出到文件
- func noOutput() bool {
- return Output == "" || Output == " "
- }
- type PingData struct {
- IP *net.IPAddr
- Sended int
- Received int
- Delay time.Duration
- Colo string
- }
- type CloudflareIPData struct {
- *PingData
- lossRate float32
- DownloadSpeed float64
- }
- // 计算丢包率
- func (cf *CloudflareIPData) getLossRate() float32 {
- if cf.lossRate == 0 {
- pingLost := cf.Sended - cf.Received
- cf.lossRate = float32(pingLost) / float32(cf.Sended)
- }
- return cf.lossRate
- }
- func (cf *CloudflareIPData) toString() []string {
- result := make([]string, 7)
- result[0] = cf.IP.String()
- result[1] = strconv.Itoa(cf.Sended)
- result[2] = strconv.Itoa(cf.Received)
- result[3] = strconv.FormatFloat(float64(cf.getLossRate()), 'f', 2, 32)
- result[4] = strconv.FormatFloat(cf.Delay.Seconds()*1000, 'f', 2, 32)
- result[5] = strconv.FormatFloat(cf.DownloadSpeed/1024/1024, 'f', 2, 32)
- // 如果 Colo 为空,则使用 "N/A" 表示
- if cf.Colo == "" {
- result[6] = "N/A"
- } else {
- result[6] = cf.Colo
- }
- return result
- }
- func ExportCsv(data []CloudflareIPData) {
- if noOutput() || len(data) == 0 {
- return
- }
- fp, err := os.Create(Output)
- if err != nil {
- log.Fatalf("创建文件[%s]失败:%v", Output, err)
- return
- }
- defer fp.Close()
- w := csv.NewWriter(fp) //创建一个新的写入文件流
- _ = w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度(MB/s)", "地区码"})
- _ = w.WriteAll(convertToString(data))
- w.Flush()
- }
- func convertToString(data []CloudflareIPData) [][]string {
- result := make([][]string, 0)
- for _, v := range data {
- result = append(result, v.toString())
- }
- return result
- }
- // 延迟丢包排序
- type PingDelaySet []CloudflareIPData
- // 延迟条件过滤
- func (s PingDelaySet) FilterDelay() (data PingDelaySet) {
- if InputMaxDelay > maxDelay || InputMinDelay < minDelay { // 当输入的延迟条件不在默认范围内时,不进行过滤
- return s
- }
- if InputMaxDelay == maxDelay && InputMinDelay == minDelay { // 当输入的延迟条件为默认值时,不进行过滤
- return s
- }
- for _, v := range s {
- if v.Delay > InputMaxDelay { // 平均延迟上限,延迟大于条件最大值时,后面的数据都不满足条件,直接跳出循环
- break
- }
- if v.Delay < InputMinDelay { // 平均延迟下限,延迟小于条件最小值时,不满足条件,跳过
- continue
- }
- data = append(data, v) // 延迟满足条件时,添加到新数组中
- }
- return
- }
- // 丢包条件过滤
- func (s PingDelaySet) FilterLossRate() (data PingDelaySet) {
- if InputMaxLossRate >= maxLossRate { // 当输入的丢包条件为默认值时,不进行过滤
- return s
- }
- for _, v := range s {
- if v.getLossRate() > InputMaxLossRate { // 丢包几率上限
- break
- }
- 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].getLossRate(), s[j].getLossRate()
- 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]
- }
- func (s DownloadSpeedSet) Print() {
- if NoPrintResult() {
- return
- }
- 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%-12s%-5s\n"
- dataFormat := "%-18s%-8s%-8s%-8s%-10s%-16s%-8s\n"
- for i := 0; i < PrintNum; i++ { // 如果要输出的 IP 中包含 IPv6,那么就需要调整一下间隔
- if len(dateString[i][0]) > 15 {
- headFormat = "%-40s%-5s%-5s%-5s%-6s%-12s%-5s\n"
- dataFormat = "%-42s%-8s%-8s%-8s%-10s%-16s%-8s\n"
- break
- }
- }
- Cyan.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], dateString[i][6])
- }
- if !noOutput() {
- fmt.Printf("\n完整测速结果已写入 %v 文件,可使用记事本/表格软件查看。\n", Output)
- }
- }
|