pingutils.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package misc
  15. import (
  16. "fmt"
  17. "net"
  18. "time"
  19. "github.com/tatsushid/go-fastping"
  20. "yunion.io/x/pkg/errors"
  21. )
  22. type SPingResult struct {
  23. addr string
  24. rtt []time.Duration
  25. count int
  26. }
  27. func NewPingResult(addr string, count int) *SPingResult {
  28. return &SPingResult{
  29. addr: addr,
  30. rtt: make([]time.Duration, 0),
  31. count: count,
  32. }
  33. }
  34. func (pr *SPingResult) Add(rtt time.Duration) {
  35. pr.rtt = append(pr.rtt, rtt)
  36. }
  37. func (pr SPingResult) Rtt() (min time.Duration, avg time.Duration, max time.Duration) {
  38. sum := time.Duration(0)
  39. max = time.Duration(-1)
  40. min = time.Duration(-1)
  41. for _, d := range pr.rtt {
  42. sum += d
  43. if max < 0 || max < d {
  44. max = d
  45. }
  46. if min < 0 || min > d {
  47. min = d
  48. }
  49. }
  50. if len(pr.rtt) > 0 {
  51. avg = sum / time.Duration(len(pr.rtt))
  52. }
  53. return
  54. }
  55. func (pr SPingResult) Loss() int {
  56. return 100 - len(pr.rtt)*100/pr.count
  57. }
  58. func (pr SPingResult) String() string {
  59. min, avg, max := pr.Rtt()
  60. return fmt.Sprintf("%d packets transmitted, %d received, %d%% packet loss, rtt min/avg/max = %d/%d/%d ms", pr.count, len(pr.rtt), pr.Loss(), min/time.Millisecond, avg/time.Millisecond, max/time.Millisecond)
  61. }
  62. func Ping(addrList []string, probeCount, timeoutSecond int, debug bool) (map[string]*SPingResult, error) {
  63. p := fastping.NewPinger()
  64. count := probeCount
  65. timeout := time.Second * time.Duration(timeoutSecond)
  66. p.MaxRTT = timeout
  67. p.Size = 64
  68. p.Debug = debug
  69. result := make(map[string]*SPingResult)
  70. for _, addr := range addrList {
  71. result[addr] = NewPingResult(addr, count)
  72. p.AddIP(addr)
  73. }
  74. p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
  75. result[addr.String()].Add(rtt)
  76. }
  77. p.OnIdle = func() {
  78. }
  79. p.RunLoop()
  80. defer p.Stop()
  81. ticker := time.NewTicker(time.Duration(count) * timeout)
  82. defer ticker.Stop()
  83. select {
  84. case <-p.Done():
  85. if err := p.Err(); err != nil {
  86. return nil, errors.Wrap(err, "ping error")
  87. }
  88. break
  89. case <-ticker.C:
  90. break
  91. }
  92. return result, nil
  93. }