diff --git a/.gitignore b/.gitignore index 859fd68..7970fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ dist Releases +*.exe +*.csv diff --git a/main.go b/main.go index eeb8abe..9efad35 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 6ac296e..02e55ee 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 0000000..6f5e4ac --- /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 eb0e13b..0000000 --- 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 8e586fd..242c9ea 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 cdb6589..cf14e27 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() + } + } +}