rebuild tcping

This commit is contained in:
mazhuang 2021-11-09 18:44:17 +08:00
parent 6f74e60444
commit 83c63e975e
5 changed files with 148 additions and 68 deletions

123
tcping.go
View File

@ -2,10 +2,10 @@ package main
import (
"context"
"fmt"
"io"
"net"
"net/http"
"strconv"
"sync"
"time"
@ -13,30 +13,24 @@ import (
)
//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()
var fullAddress string
fullAddress := fmt.Sprintf("%s:%d", ip.String(), tcpPort)
//fmt.Println(ip.String())
if ipv6Mode { // IPv6 需要加上 []
fullAddress = "[" + ip.String() + "]:" + strconv.Itoa(tcpPort)
} else {
fullAddress = ip.String() + ":" + strconv.Itoa(tcpPort)
fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), tcpPort)
}
conn, err := net.DialTimeout("tcp", fullAddress, tcpConnectTimeout)
if err != nil {
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
func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) {
pingRecv := 0
var pingTime float32 = 0.0
func checkConnection(ip net.IPAddr, tcpPort int) (pingRecv int, pingTime time.Duration) {
for i := 1; i <= failTime; i++ {
pingSucceed, pingTimeCurrent := tcping(ip, tcpPort)
if pingSucceed {
@ -44,14 +38,14 @@ func checkConnection(ip net.IPAddr, tcpPort int) (int, float32) {
pingTime += pingTimeCurrent
}
}
return pingRecv, pingTime
return
}
//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
pingRecv := 0
var pingTime float32 = 0.0
var pingTime time.Duration
for !ipCanConnect {
pingRecvCurrent, pingTimeCurrent := checkConnection(ip, tcpPort)
if pingRecvCurrent != 0 {
@ -66,21 +60,20 @@ func tcpingHandler(ip net.IPAddr, tcpPort int, pingCount int, progressHandler fu
break
}
}
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 {
if !ipCanConnect {
progressHandler(NoAvailableIPFound)
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)) {
@ -126,47 +119,47 @@ func DownloadSpeedHandler(ip net.IPAddr) (bool, float32) {
response, err := client.Get(url)
if err != nil {
return false, 0
} else {
defer func() { _ = response.Body.Close() }()
if response.StatusCode == 200 {
timeStart := time.Now()
timeEnd := timeStart.Add(downloadTestTime)
}
defer response.Body.Close()
if response.StatusCode != 200 {
return false, 0
}
timeStart := time.Now()
timeEnd := timeStart.Add(downloadTestTime)
contentLength := response.ContentLength
buffer := make([]byte, downloadBufferSize)
contentLength := response.ContentLength
buffer := make([]byte, downloadBufferSize)
var contentRead int64 = 0
var timeSlice = downloadTestTime / 100
var timeCounter = 1
var lastContentRead int64 = 0
var (
contentRead int64 = 0
timeSlice = downloadTestTime / 100
timeCounter = 1
lastContentRead int64 = 0
)
var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
e := ewma.NewMovingAverage()
var nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
e := ewma.NewMovingAverage()
for contentLength != contentRead {
var currentTime = time.Now()
if currentTime.After(nextTime) {
timeCounter += 1
nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
e.Add(float64(contentRead - lastContentRead))
lastContentRead = contentRead
}
if currentTime.After(timeEnd) {
break
}
bufferRead, err := response.Body.Read(buffer)
contentRead += int64(bufferRead)
if err != nil {
if err != io.EOF {
break
} else {
e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice)))
}
}
for contentLength != contentRead {
var currentTime = time.Now()
if currentTime.After(nextTime) {
timeCounter++
nextTime = timeStart.Add(timeSlice * time.Duration(timeCounter))
e.Add(float64(contentRead - lastContentRead))
lastContentRead = contentRead
}
if currentTime.After(timeEnd) {
break
}
bufferRead, err := response.Body.Read(buffer)
contentRead += int64(bufferRead)
if err != nil {
if err != io.EOF {
break
}
return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120)
} else {
return false, 0
e.Add(float64(contentRead-lastContentRead) / (float64(nextTime.Sub(currentTime)) / float64(timeSlice)))
}
}
return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 120)
}

19
tcping/tcping.go Normal file
View 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)
}

View File

@ -18,7 +18,7 @@ type CloudflareIPData struct {
pingReceived int
recvRate float32
downloadSpeed float32
pingTime float32
pingTime time.Duration
}
func (cf *CloudflareIPData) getRecvRate() float32 {
@ -32,7 +32,7 @@ func (cf *CloudflareIPData) getRecvRate() float32 {
func ExportCsv(filePath string, data []CloudflareIPData) {
fp, err := os.Create(filePath)
if err != nil {
log.Fatalf("创建文件["+filePath+"]句柄失败,%v", err)
log.Fatalf("创建文件[%s]失败:%v", filePath, err)
return
}
defer fp.Close()
@ -48,7 +48,7 @@ func (cf *CloudflareIPData) toString() []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] = 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)
return result
}

59
utils/csv.go Normal file
View 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
View File

@ -0,0 +1,9 @@
package utils
type ProgressEvent int
const (
NoAvailableIPFound ProgressEvent = iota
AvailableIPFound
NormalPing
)