Skip to content
This repository has been archived by the owner on Aug 7, 2022. It is now read-only.

Commit

Permalink
新增下载测速功能
Browse files Browse the repository at this point in the history
  • Loading branch information
Spedoske committed Jul 9, 2020
1 parent 839f48e commit 5c67f34
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 71 deletions.
41 changes: 41 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
before:
hooks:
# you may remove this if you don't use vgo
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
id: "CloudflareScanner"
binary: "CloudflareScanner"
goos:
- darwin
- freebsd
- linux
- windows
goarch:
- 386
- amd64
- arm
#hooks:
#post: ./compile.bat "{{ dir .Path }}"
archives:
- replacements:
darwin: MacOS
linux: Linux
windows: Windows
386: x86
amd64: x64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "v1.1.0"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
2 changes: 1 addition & 1 deletion IPRangeLoader.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func loadFirstIPOfRangeFromFile() []net.IPAddr {
if err != nil {
log.Fatal(err)
}
firstIP[15]=ipEndWith
firstIP[15] = ipEndWith
for IPRange.Contains(firstIP) {
firstIPCopy := make([]byte, len(firstIP))
copy(firstIPCopy, firstIP)
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module CloudflareIPScanner

go 1.14

require github.com/cheggaaa/pb/v3 v3.0.4
require (
github.com/VividCortex/ewma v1.1.1
github.com/cheggaaa/pb/v3 v3.0.4
)
98 changes: 43 additions & 55 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,79 +1,67 @@
package main

import (
"encoding/csv"
"fmt"
"github.com/cheggaaa/pb/v3"
"log"
"os"
"sort"
"sync"
"time"
)

func ExportCsv(filePath string, data [][]string) {
fp, err := os.Create(filePath)
if err != nil {
log.Fatalf("创建文件["+filePath+"]句柄失败,%v", err)
return
}
defer fp.Close()
w := csv.NewWriter(fp) //创建一个新的写入文件流
w.WriteAll(data)
w.Flush()
}

var pingTime int
var pingRoutine int
const ipEndWith uint8 = 1
type progressEvent int
const (
NoAvailableIPFound progressEvent = iota
AvailableIPFound
NormalPing
)

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()
}
}
}

func handleUserInput(){
fmt.Println("请输入扫描协程数(数字越大越快,默认100):")
func handleUserInput() {
fmt.Println("请输入扫描协程数(数字越大越快,默认400):")
fmt.Scanln(&pingRoutine)
if pingRoutine<=0{
pingRoutine=100
if pingRoutine <= 0 {
pingRoutine = 400
}
fmt.Println("请输入tcping次数(默认10):")
fmt.Scanln(&pingTime)
if pingTime<=0{
pingTime=10
if pingTime <= 0 {
pingTime = 10
}
fmt.Println("请输入要测试的下载节点个数(默认10):")
fmt.Scanln(&downloadTestCount)
if downloadTestCount <= 0 {
downloadTestCount = 10
}
fmt.Println("请输入下载测试时间(默认10,单位为秒):")
var downloadSecond int64
fmt.Scanln(&downloadSecond)
if downloadSecond <= 0 {
downloadSecond = 10
}
downloadTestTime = time.Duration(downloadSecond) * time.Second
}

func main(){
func main() {
initipEndWith()
handleUserInput()
ips:=loadFirstIPOfRangeFromFile()
pingCount:=len(ips)*pingTime
ips := loadFirstIPOfRangeFromFile()
pingCount := len(ips) * pingTime
bar := pb.StartNew(pingCount)
var wg sync.WaitGroup
var mu sync.Mutex
var data = make([][]string,0)
data = append(data,[]string{"IP Address","Ping received","Ping time"})
control := make(chan bool,pingRoutine)
for _,ip :=range ips{
var data = make([]CloudflareIPData, 0)

fmt.Println("开始tcping")

control := make(chan bool, pingRoutine)
for _, ip := range ips {
wg.Add(1)
control<-false
handleProgress:=handleProgressGenerator(bar)
go tcpingGoroutine(&wg,&mu,ip,pingTime, &data,control,handleProgress)
control <- false
handleProgress := handleProgressGenerator(bar)
go tcpingGoroutine(&wg, &mu, ip, pingTime, &data, control, handleProgress)
}
wg.Wait()
bar.Finish()
ExportCsv("./result.csv",data)
bar = pb.StartNew(downloadTestCount)
sort.Sort(CloudflareIPDataSet(data))
fmt.Println("开始下载测速")
for i := 0; i < downloadTestCount; i++ {
_, speed := DownloadSpeedHandler(data[i].ip)
data[i].downloadSpeed = speed
bar.Add(1)
}
bar.Finish()
ExportCsv("./result.csv", data)
}
100 changes: 86 additions & 14 deletions tcping.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
package main

import (
"context"
"github.com/VividCortex/ewma"
"io"
"net"
"net/http"
"strconv"
"sync"
"time"
)

const defaultTcpPort = 443
const tcpConnectTimeout = time.Second * 1
const failTime = 4

//bool connectionSucceed float64 time
func tcping(ip net.IPAddr) (bool, float64) {
//bool connectionSucceed float32 time
func tcping(ip net.IPAddr) (bool, float32) {
startTime := time.Now()
conn, err := net.DialTimeout("tcp", ip.String()+":"+strconv.Itoa(defaultTcpPort), tcpConnectTimeout)
if err != nil {
return false, 0
} else {
var endTime = time.Since(startTime)
var duration = float64(endTime.Microseconds()) / 1000.0
var duration = float32(endTime.Microseconds()) / 1000.0
_ = conn.Close()
return true, duration
}
}

//pingReceived pingTotalTime
func checkConnection(ip net.IPAddr) (int, float64) {
func checkConnection(ip net.IPAddr) (int, float32) {
pingRecv := 0
pingTime := 0.0
var pingTime float32 = 0.0
for i := 1; i <= failTime; i++ {
pingSucceed, pingTimeCurrent := tcping(ip)
if pingSucceed {
Expand All @@ -40,10 +40,10 @@ func checkConnection(ip net.IPAddr) (int, float64) {
}

//return Success packetRecv averagePingTime specificIPAddr
func tcpingHandler(ip net.IPAddr, pingCount int, progressHandler func(e progressEvent)) (bool, int, float64, net.IPAddr) {
func tcpingHandler(ip net.IPAddr, pingCount int, progressHandler func(e progressEvent)) (bool, int, float32, net.IPAddr) {
ipCanConnect := false
pingRecv := 0
pingTime := 0.0
var pingTime float32 = 0.0
for !ipCanConnect {
pingRecvCurrent, pingTimeCurrent := checkConnection(ip)
if pingRecvCurrent != 0 {
Expand All @@ -68,20 +68,92 @@ func tcpingHandler(ip net.IPAddr, pingCount int, progressHandler func(e progress
pingTime += pingTimeCurrent
}
}
return true, pingRecv, pingTime / float64(pingRecv), ip
return true, pingRecv, pingTime / float32(pingRecv), ip
} else {
progressHandler(NoAvailableIPFound)
return false, 0, 0, net.IPAddr{}
}
}

func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, pingCount int, csv *[][]string, control chan bool, progressHandler func(e progressEvent)) {
func tcpingGoroutine(wg *sync.WaitGroup, mutex *sync.Mutex, ip net.IPAddr, pingCount int, csv *[]CloudflareIPData, control chan bool, progressHandler func(e progressEvent)) {
defer wg.Done()
success, pingRecv, pingTimeAvg, currentIP := tcpingHandler(ip, pingCount, progressHandler)
if success {
mutex.Lock()
*csv = append(*csv, []string{currentIP.String(), strconv.Itoa(pingRecv), strconv.FormatFloat(pingTimeAvg, 'f', 4, 64)})
var cfdata CloudflareIPData
cfdata.ip = currentIP
cfdata.pingReceived = pingRecv
cfdata.pingTime = pingTimeAvg
cfdata.pingCount = pingCount
*csv = append(*csv, cfdata)
mutex.Unlock()
}
<-control
}

func GetDialContextByAddr(fakeSourceAddr string) func(ctx context.Context, network, address string) (net.Conn, error) {
return func(ctx context.Context, network, address string) (net.Conn, error) {
c, e := (&net.Dialer{}).DialContext(ctx, network, fakeSourceAddr)
return c, e
}
}

//bool : can download,float32 downloadSpeed
func DownloadSpeedHandler(ip net.IPAddr) (bool, float32) {
var client = http.Client{
Transport: nil,
CheckRedirect: nil,
Jar: nil,
Timeout: 0,
}
client.Transport = &http.Transport{
DialContext: GetDialContextByAddr(ip.String() + ":443"),
}
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)

contentLength := response.ContentLength
buffer := make([]byte, downloadBufferSize)

var contentRead int64 = 0
var timeSlice = downloadTestTime / 100
var timeCounter = 1
var lastContentRead int64 = 0

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)))
}
}
}
return true, float32(e.Value()) / (float32(downloadTestTime.Seconds()) / 100)
} else {
return false, 0
}
}
}
Loading

0 comments on commit 5c67f34

Please # to comment.