CloudflareSpeedTest/task/tcping.go

148 lines
3.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package task
import (
"fmt"
"net"
"sort"
"strconv"
"sync"
"time"
"github.com/XIU2/CloudflareSpeedTest/utils"
)
const (
tcpConnectTimeout = time.Second * 1
maxRoutine = 1000
defaultRoutines = 200
defaultPort = 443
defaultPingTimes = 4
)
var (
Routines = defaultRoutines
TCPPort int = defaultPort
PingTimes int = defaultPingTimes
)
type Ping struct {
wg *sync.WaitGroup
m *sync.Mutex
ips []*net.IPAddr
csv utils.PingDelaySet
control chan bool
bar *utils.Bar
}
func checkPingDefault() {
if Routines <= 0 {
Routines = defaultRoutines
}
if TCPPort <= 0 || TCPPort >= 65535 {
TCPPort = defaultPort
}
if PingTimes <= 0 {
PingTimes = defaultPingTimes
}
}
func NewPing() *Ping {
checkPingDefault()
ips := loadIPRanges()
return &Ping{
wg: &sync.WaitGroup{},
m: &sync.Mutex{},
ips: ips,
csv: make(utils.PingDelaySet, 0),
control: make(chan bool, Routines),
bar: utils.NewBar(len(ips), "可用:", ""),
}
}
func (p *Ping) Run() utils.PingDelaySet {
if len(p.ips) == 0 {
return p.csv
}
if Httping {
fmt.Printf("开始延迟测速模式HTTP, 端口:%d, 范围:%v ~ %v ms, 丢包:%.2f)\n", TCPPort, utils.InputMinDelay.Milliseconds(), utils.InputMaxDelay.Milliseconds(), utils.InputMaxLossRate)
} else {
fmt.Printf("开始延迟测速模式TCP, 端口:%d, 范围:%v ~ %v ms, 丢包:%.2f)\n", TCPPort, utils.InputMinDelay.Milliseconds(), utils.InputMaxDelay.Milliseconds(), utils.InputMaxLossRate)
}
for _, ip := range p.ips {
p.wg.Add(1)
p.control <- false
go p.start(ip)
}
p.wg.Wait()
p.bar.Done()
sort.Sort(p.csv)
return p.csv
}
func (p *Ping) start(ip *net.IPAddr) {
defer p.wg.Done()
p.tcpingHandler(ip)
<-p.control
}
// bool connectionSucceed float32 time
func (p *Ping) tcping(ip *net.IPAddr) (bool, time.Duration) {
startTime := time.Now()
var fullAddress string
if isIPv4(ip.String()) {
fullAddress = fmt.Sprintf("%s:%d", ip.String(), TCPPort)
} else {
fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), 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) (recv int, totalDelay time.Duration) {
if Httping {
recv, totalDelay = p.httping(ip)
return
}
for i := 0; i < PingTimes; i++ {
if ok, delay := p.tcping(ip); ok {
recv++
totalDelay += delay
}
}
return
}
func (p *Ping) appendIPData(data *utils.PingData) {
p.m.Lock()
defer p.m.Unlock()
p.csv = append(p.csv, utils.CloudflareIPData{
PingData: data,
})
}
// handle tcping
func (p *Ping) tcpingHandler(ip *net.IPAddr) {
recv, totalDlay := p.checkConnection(ip)
nowAble := len(p.csv)
if recv != 0 {
nowAble++
}
p.bar.Grow(1, strconv.Itoa(nowAble))
if recv == 0 {
return
}
data := &utils.PingData{
IP: ip,
Sended: PingTimes,
Received: recv,
Delay: totalDlay / time.Duration(recv),
}
p.appendIPData(data)
}