mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 11:07:40 +08:00
feat: connection quality test.
This commit is contained in:
parent
6e4bbb9e42
commit
6570d10dc4
@ -242,7 +242,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
for i := range cli.servers {
|
for i := range cli.servers {
|
||||||
go func(index int) {
|
go func(index int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
p, err := qualityTest(cli.servers[index])
|
p, err := qualityTest(cli.servers[index].String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pings[index] = 9999
|
pings[index] = 9999
|
||||||
return
|
return
|
||||||
|
@ -488,10 +488,10 @@ func getSSOAddress() ([]*net.TCPAddr, error) {
|
|||||||
return adds, nil
|
return adds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func qualityTest(addr *net.TCPAddr) (int64, error) {
|
func qualityTest(addr string) (int64, error) {
|
||||||
// see QualityTestManager
|
// see QualityTestManager
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
conn, err := net.DialTimeout("tcp", addr.String(), time.Second*5)
|
conn, err := net.DialTimeout("tcp", addr, time.Second*5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "failed to connect to server during quality test")
|
return 0, errors.Wrap(err, "failed to connect to server during quality test")
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -12,6 +15,74 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ConnectionQualityInfo 客户端连接质量测试结果
|
||||||
|
// 延迟单位为 ms 如为 9999 则测试失败 测试方法为 TCP 连接测试
|
||||||
|
// 丢包测试方法为 ICMP. 总共发送 10 个包, 记录丢包数
|
||||||
|
type ConnectionQualityInfo struct {
|
||||||
|
// ChatServerLatency 聊天服务器延迟
|
||||||
|
ChatServerLatency int64
|
||||||
|
// ChatServerPacketLoss 聊天服务器ICMP丢包数
|
||||||
|
ChatServerPacketLoss int
|
||||||
|
// LongMessageServerLatency 长消息服务器延迟. 涉及长消息以及合并转发消息下载
|
||||||
|
LongMessageServerLatency int64
|
||||||
|
// LongMessageServerResponseLatency 长消息服务器返回延迟
|
||||||
|
LongMessageServerResponseLatency int64
|
||||||
|
// SrvServerLatency Highway服务器延迟. 涉及媒体以及群文件上传
|
||||||
|
SrvServerLatency int64
|
||||||
|
// SrvServerPacketLoss Highway服务器ICMP丢包数.
|
||||||
|
SrvServerPacketLoss int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
|
||||||
|
if !c.Online {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := &ConnectionQualityInfo{}
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
go func(w *sync.WaitGroup) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if r.ChatServerLatency, err = qualityTest(c.servers[c.currServerIndex].String()); err != nil {
|
||||||
|
c.Error("test chat server latency error: %v", err)
|
||||||
|
r.ChatServerLatency = 9999
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr, err := net.ResolveIPAddr("ip", "ssl.htdata.qq.com"); err == nil {
|
||||||
|
if r.LongMessageServerLatency, err = qualityTest((&net.TCPAddr{IP: addr.IP, Port: 443}).String()); err != nil {
|
||||||
|
c.Error("test long message server latency error: %v", err)
|
||||||
|
r.LongMessageServerLatency = 9999
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.Error("resolve long message server error: %v", err)
|
||||||
|
r.LongMessageServerLatency = 9999
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.SrvServerLatency, err = qualityTest(c.srvSsoAddrs[0]); err != nil {
|
||||||
|
c.Error("test srv server latency error: %v", err)
|
||||||
|
r.SrvServerLatency = 9999
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Done()
|
||||||
|
}(&wg)
|
||||||
|
go func(w *sync.WaitGroup) {
|
||||||
|
res := utils.RunICMPPingLoop(&net.IPAddr{IP: c.servers[c.currServerIndex].IP}, 10)
|
||||||
|
r.ChatServerPacketLoss = res.PacketsLoss
|
||||||
|
res = utils.RunICMPPingLoop(&net.IPAddr{IP: net.ParseIP(strings.Split(c.srvSsoAddrs[0], ":")[0])}, 10)
|
||||||
|
r.SrvServerPacketLoss = res.PacketsLoss
|
||||||
|
w.Done()
|
||||||
|
}(&wg)
|
||||||
|
start := time.Now()
|
||||||
|
if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil {
|
||||||
|
r.LongMessageServerResponseLatency = time.Now().Sub(start).Milliseconds()
|
||||||
|
} else {
|
||||||
|
c.Error("test long message server response latency error: %v", err)
|
||||||
|
r.LongMessageServerResponseLatency = 9999
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// connect 连接到 QQClient.servers 中的服务器
|
// connect 连接到 QQClient.servers 中的服务器
|
||||||
func (c *QQClient) connect() error {
|
func (c *QQClient) connect() error {
|
||||||
c.Info("connect to server: %v", c.servers[c.currServerIndex].String())
|
c.Info("connect to server: %v", c.servers[c.currServerIndex].String())
|
||||||
|
3
go.mod
3
go.mod
@ -3,11 +3,10 @@ module github.com/Mrs4s/MiraiGo
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
github.com/tidwall/gjson v1.8.1
|
github.com/tidwall/gjson v1.8.1
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
)
|
)
|
||||||
|
8
go.sum
8
go.sum
@ -49,6 +49,8 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
|
|||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -57,7 +59,13 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cO
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
72
utils/icmp.go
Normal file
72
utils/icmp.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/net/icmp"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ICMPPingResult struct {
|
||||||
|
PacketsSent int
|
||||||
|
PacketsRecv int
|
||||||
|
PacketsLoss int
|
||||||
|
Rtts []int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunICMPPingLoop(addr *net.IPAddr, count int) *ICMPPingResult {
|
||||||
|
if count <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := &ICMPPingResult{
|
||||||
|
PacketsSent: count,
|
||||||
|
Rtts: make([]int64, count),
|
||||||
|
}
|
||||||
|
for i := 1; i <= count; i++ {
|
||||||
|
rtt, err := SendICMPRequest(addr, i)
|
||||||
|
if err != nil {
|
||||||
|
r.PacketsLoss++
|
||||||
|
r.Rtts[i-1] = 9999
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.PacketsRecv++
|
||||||
|
r.Rtts[i-1] = rtt
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendICMPRequest(addr *net.IPAddr, seq int) (int64, error) {
|
||||||
|
data := make([]byte, 32)
|
||||||
|
rand.Read(data)
|
||||||
|
body := &icmp.Echo{
|
||||||
|
ID: 0,
|
||||||
|
Seq: seq,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
msg := &icmp.Message{
|
||||||
|
Type: ipv4.ICMPTypeEcho,
|
||||||
|
Code: 0,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
msgBytes, _ := msg.Marshal(nil)
|
||||||
|
conn, err := net.DialIP("ip4:icmp", nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(err, "dial icmp conn error")
|
||||||
|
}
|
||||||
|
defer func() { _ = conn.Close() }()
|
||||||
|
if _, err = conn.Write(msgBytes); err != nil {
|
||||||
|
return 0, errors.Wrap(err, "write icmp packet error")
|
||||||
|
}
|
||||||
|
start := time.Now()
|
||||||
|
_ = conn.SetReadDeadline(time.Now().Add(time.Second * 2))
|
||||||
|
buff := make([]byte, 1024)
|
||||||
|
_, err = conn.Read(buff)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(err, "read icmp conn error")
|
||||||
|
}
|
||||||
|
duration := time.Now().Sub(start).Milliseconds()
|
||||||
|
return duration, nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user