Files
CloudflareSpeedTest/task/tcping.go
kaka f4f1fdcd80 新增 HTTPing 延迟测速模式(beta); 新增 IP 机场三字码 colo 筛选功能(beta) (#282)
这两个功能目前仅为测试版,后续会大幅改动,以最终成品为准~
2023-01-31 12:48:28 +08:00

148 lines
3.0 KiB
Go
Raw 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"
"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), "可用IP:", ""),
}
}
func (p *Ping) Run() utils.PingDelaySet {
if len(p.ips) == 0 {
return p.csv
}
if Httping {
fmt.Printf("开始延迟测速模式HTTP端口80平均延迟上限%v ms平均延迟下限%v ms)\n", utils.InputMaxDelay.Milliseconds(), utils.InputMinDelay.Milliseconds())
} else {
fmt.Printf("开始延迟测速模式TCP端口%d平均延迟上限%v ms平均延迟下限%v ms)\n", TCPPort, utils.InputMaxDelay.Milliseconds(), utils.InputMinDelay.Milliseconds())
}
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)
}