latency_measurer.go 2.2 KB

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