mirror of
https://github.com/XIU2/CloudflareSpeedTest.git
synced 2026-03-23 08:01:01 +08:00
rebuild tcping
This commit is contained in:
123
tcping.go
123
tcping.go
@@ -2,10 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -13,30 +13,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//bool connectionSucceed float32 time
|
//bool connectionSucceed float32 time
|
||||||
func tcping(ip net.IPAddr, tcpPort int) (bool, float32) {
|
func tcping(ip net.IPAddr, tcpPort int) (bool, time.Duration) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
var fullAddress string
|
fullAddress := fmt.Sprintf("%s:%d", ip.String(), tcpPort)
|
||||||
//fmt.Println(ip.String())
|
//fmt.Println(ip.String())
|
||||||
if ipv6Mode { // IPv6 需要加上 []
|
if ipv6Mode { // IPv6 需要加上 []
|
||||||
fullAddress = "[" + ip.String() + "]:" + strconv.Itoa(tcpPort)
|
fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), tcpPort)
|
||||||
} else {
|
|
||||||
fullAddress = ip.String() + ":" + strconv.Itoa(tcpPort)
|
|
||||||
}
|
}
|
||||||
conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout)
|
conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, 0
|
return false, 0
|
||||||
} else {
|
|
||||||
var endTime = time.Since(startTime)
|
|
||||||
var duration = float32(endTime.Microseconds()) / 1000.0
|
|
||||||
_ = conn.Close()
|
|
||||||
return true, duration
|
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
return true, duration
|
||||||
}
|
}
|
||||||
|
|
||||||
//pingReceived pingTotalTime
|
//pingReceived pingTotalTime
|
||||||
func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) {
|
func checkConnection(ip net.IPAddr, tcpPort int) (pingRecv int, pingTime time.Duration) {
|
||||||
pingRecv := 0
|
|
||||||
var pingTime float32 = 0.0
|
|
||||||
for i := 1; i <= failTime; i++ {
|
for i := 1; i <= failTime; i++ {
|
||||||
pingSucceed, pingTimeCurrent := tcping(ip, tcpPort)
|
pingSucceed, pingTimeCurrent := tcping(ip, tcpPort)
|
||||||
if pingSucceed {
|
if pingSucceed {
|
||||||
@@ -44,14 +38,14 @@ func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) {
|
|||||||
pingTime += pingTimeCurrent
|
pingTime += pingTimeCurrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pingRecv, pingTime
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//return Success packetRecv averagePingTime specificIPAddr
|
//return Success packetRecv averagePingTime specificIPAddr
|
||||||
func tcpingHandler(ip net.IPAddr, tcpPort int, pingCount int, progressHandler func(e progressEvent)) (bool, int, float32, net.IPAddr) {
|
func tcpingHandler(ip net.IPAddr, tcpPort, pingCount int, progressHandler func(e progressEvent)) (bool, int, time.Duration, net.IPAddr) {
|
||||||
ipCanConnect := false
|
ipCanConnect := false
|
||||||
pingRecv := 0
|
pingRecv := 0
|
||||||
var pingTime float32 = 0.0
|
var pingTime time.Duration
|
||||||
for !ipCanConnect {
|
for !ipCanConnect {
|
||||||
pingRecvCurrent, pingTimeCurrent := checkConnection(ip, tcpPort)
|
pingRecvCurrent, pingTimeCurrent := checkConnection(ip, tcpPort)
|
||||||
if pingRecvCurrent != 0 {
|
if pingRecvCurrent != 0 {
|
||||||
@@ -66,21 +60,20 @@ func tcpingHandler(ip net.IPAddr, tcpPort int, pingCount int, progressHandler fu
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ipCanConnect {
|
if !ipCanConnect {
|
||||||
progressHandler(AvailableIPFound)
|
|
||||||
for i := failTime; i < pingCount; i++ {
|
|
||||||
pingSuccess, pingTimeCurrent := tcping(ip, tcpPort)
|
|
||||||
progressHandler(NormalPing)
|
|
||||||
if pingSuccess {
|
|
||||||
pingRecv++
|
|
||||||
pingTime += pingTimeCurrent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true, pingRecv, pingTime / float32(pingRecv), ip
|
|
||||||
} else {
|
|
||||||
progressHandler(NoAvailableIPFound)
|
progressHandler(NoAvailableIPFound)
|
||||||
return false, 0, 0, net.IPAddr{}
|
return false, 0, 0, net.IPAddr{}
|
||||||
}
|
}
|
||||||
|
progressHandler(AvailableIPFound)
|
||||||
|
for i := failTime; i < pingCount; i++ {
|
||||||
|
pingSuccess, pingTimeCurrent := tcping(ip, tcpPort)
|
||||||
|
progressHandler(NormalPing)
|
||||||
|
if pingSuccess {
|
||||||
|
pingRecv++
|
||||||
|
pingTime += pingTimeCurrent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, pingRecv, pingTime / time.Duration(pingRecv), ip
|
||||||
}
|
}
|
||||||
|
|
||||||
func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, tcpPort int, 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)) {
|
||||||
@@ -126,47 +119,47 @@ func DownloadSpeedHandler(ip net.IPAddr) (bool, float32) {
|
|||||||
response, err := client.Get(url)
|
response, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, 0
|
return false, 0
|
||||||
} else {
|
}
|
||||||
defer func() { _ = response.Body.Close() }()
|
defer response.Body.Close()
|
||||||
if response.StatusCode == 200 {
|
if response.StatusCode != 200 {
|
||||||
timeStart := time.Now()
|
return false, 0
|
||||||
timeEnd := timeStart.Add(downloadTestTime)
|
}
|
||||||
|
timeStart := time.Now()
|
||||||
|
timeEnd := timeStart.Add(downloadTestTime)
|
||||||
|
|
||||||
contentLength := response.ContentLength
|
contentLength := response.ContentLength
|
||||||
buffer := make([]byte, downloadBufferSize)
|
buffer := make([]byte, downloadBufferSize)
|
||||||
|
|
||||||
var contentRead int64 = 0
|
var (
|
||||||
var timeSlice = downloadTestTime / 100
|
contentRead int64 = 0
|
||||||
var timeCounter = 1
|
timeSlice = downloadTestTime / 100
|
||||||
var lastContentRead int64 = 0
|
timeCounter = 1
|
||||||
|
lastContentRead int64 = 0
|
||||||
|
)
|
||||||
|
|
||||||
var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
|
var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
|
||||||
e := ewma.NewMovingAverage()
|
e := ewma.NewMovingAverage()
|
||||||
|
|
||||||
for contentLength != contentRead {
|
for contentLength != contentRead {
|
||||||
var currentTime = time.Now()
|
var currentTime = time.Now()
|
||||||
if currentTime.After(nextTime) {
|
if currentTime.After(nextTime) {
|
||||||
timeCounter += 1
|
timeCounter++
|
||||||
nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
|
nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
|
||||||
e.Add(float64(contentRead - lastContentRead))
|
e.Add(float64(contentRead - lastContentRead))
|
||||||
lastContentRead = contentRead
|
lastContentRead = contentRead
|
||||||
}
|
}
|
||||||
if currentTime.After(timeEnd) {
|
if currentTime.After(timeEnd) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
bufferRead, err := response.Body.Read(buffer)
|
bufferRead, err := response.Body.Read(buffer)
|
||||||
contentRead += int64(bufferRead)
|
contentRead += int64(bufferRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120)
|
e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice)))
|
||||||
} else {
|
|
||||||
return false, 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
19
tcping/tcping.go
Normal file
19
tcping/tcping.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
6
util.go
6
util.go
@@ -18,7 +18,7 @@ type CloudflareIPData struct {
|
|||||||
pingReceived int
|
pingReceived int
|
||||||
recvRate float32
|
recvRate float32
|
||||||
downloadSpeed float32
|
downloadSpeed float32
|
||||||
pingTime float32
|
pingTime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cf *CloudflareIPData) getRecvRate() float32 {
|
func (cf *CloudflareIPData) getRecvRate() float32 {
|
||||||
@@ -32,7 +32,7 @@ func (cf *CloudflareIPData) getRecvRate() float32 {
|
|||||||
func ExportCsv(filePath string, data []CloudflareIPData) {
|
func ExportCsv(filePath string, data []CloudflareIPData) {
|
||||||
fp, err := os.Create(filePath)
|
fp, err := os.Create(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("创建文件["+filePath+"]句柄失败,%v", err)
|
log.Fatalf("创建文件[%s]失败:%v", filePath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer fp.Close()
|
defer fp.Close()
|
||||||
@@ -48,7 +48,7 @@ func (cf *CloudflareIPData) toString() []string {
|
|||||||
result[1] = strconv.Itoa(cf.pingCount)
|
result[1] = strconv.Itoa(cf.pingCount)
|
||||||
result[2] = strconv.Itoa(cf.pingReceived)
|
result[2] = strconv.Itoa(cf.pingReceived)
|
||||||
result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32)
|
result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32)
|
||||||
result[4] = strconv.FormatFloat(float64(cf.pingTime), 'f', 2, 32)
|
result[4] = cf.pingTime.String()
|
||||||
result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32)
|
result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
59
utils/csv.go
Normal file
59
utils/csv.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CloudflareIPData struct {
|
||||||
|
ip net.IPAddr
|
||||||
|
pingCount int
|
||||||
|
pingReceived int
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return cf.recvRate
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExportCsv(filePath string, data []CloudflareIPData) {
|
||||||
|
fp, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("创建文件[%s]失败:%v", filePath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer fp.Close()
|
||||||
|
w := csv.NewWriter(fp) //创建一个新的写入文件流
|
||||||
|
w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"})
|
||||||
|
w.WriteAll(convertToString(data))
|
||||||
|
w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
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[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32)
|
||||||
|
result[4] = cf.pingTime.String()
|
||||||
|
result[5] = strconv.FormatFloat(float64(cf.downloadSpeed)/1024/1024, 'f', 2, 32)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertToString(data []CloudflareIPData) [][]string {
|
||||||
|
result := make([][]string, 0)
|
||||||
|
for _, v := range data {
|
||||||
|
result = append(result, v.toString())
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
9
utils/progress.go
Normal file
9
utils/progress.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
type ProgressEvent int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoAvailableIPFound ProgressEvent = iota
|
||||||
|
AvailableIPFound
|
||||||
|
NormalPing
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user