latency_measurer.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package ws
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/gorilla/websocket"
  6. "sync"
  7. "time"
  8. )
  9. const (
  10. maxMessageSize = 1024 * 1024 * 10 // 1MB
  11. basePingInterval = 5 * time.Second
  12. maxPingInterval = 120 * time.Second
  13. minPingInterval = 15 * time.Second
  14. )
  15. // LatencyMeasurer 延迟测量器
  16. type LatencyMeasurer struct {
  17. measurements []time.Duration
  18. lastLatency time.Duration
  19. mu sync.Mutex
  20. lastPingTime time.Time // 最后一次发送Ping的时间
  21. maxMeasurements int // 保留的最大测量次数
  22. }
  23. func NewLatencyMeasurer(windowSize int) *LatencyMeasurer {
  24. return &LatencyMeasurer{
  25. maxMeasurements: windowSize,
  26. measurements: make([]time.Duration, 0, windowSize),
  27. lastLatency: basePingInterval,
  28. }
  29. }
  30. // 发送Ping并记录时间戳
  31. func (lm *LatencyMeasurer) SendPing(conn *websocket.Conn) error {
  32. lm.mu.Lock()
  33. defer lm.mu.Unlock()
  34. if conn == nil {
  35. return errors.New("connection closed")
  36. }
  37. // 发送Ping消息
  38. err := conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWaitTimeout))
  39. if err != nil {
  40. return err
  41. }
  42. lm.lastPingTime = time.Now()
  43. return nil
  44. }
  45. // 处理Pong响应
  46. func (lm *LatencyMeasurer) CalculateLatency() {
  47. lm.mu.Lock()
  48. defer lm.mu.Unlock()
  49. if lm.lastPingTime.IsZero() {
  50. return
  51. }
  52. // 计算往返时间
  53. rtt := time.Since(lm.lastPingTime)
  54. // 维护滑动窗口
  55. if len(lm.measurements) >= lm.maxMeasurements {
  56. lm.measurements = lm.measurements[1:]
  57. }
  58. lm.measurements = append(lm.measurements, rtt)
  59. // 计算平均延迟(可根据需求改为中位数等)
  60. sum := time.Duration(0)
  61. for _, d := range lm.measurements {
  62. sum += d
  63. }
  64. lm.lastLatency = sum / time.Duration(len(lm.measurements))
  65. if lm.lastLatency > maxPingInterval {
  66. lm.lastLatency = maxPingInterval
  67. }
  68. if lm.lastLatency < minPingInterval {
  69. lm.lastLatency = minPingInterval
  70. }
  71. }
  72. // 获取当前网络延迟估值
  73. func (lm *LatencyMeasurer) GetLatency() time.Duration {
  74. lm.mu.Lock()
  75. defer lm.mu.Unlock()
  76. return lm.lastLatency
  77. }
  78. // 在连接初始化时设置Pong处理器
  79. func SetupLatencyMeasurement(conn *websocket.Conn) *LatencyMeasurer {
  80. lm := NewLatencyMeasurer(5) // 使用最近5次测量的滑动窗口
  81. conn.SetPongHandler(func(appData string) error {
  82. fmt.Println("Pong received")
  83. lm.CalculateLatency()
  84. return nil
  85. })
  86. return lm
  87. }