分享
  1. 首页
  2. 文章

实现支持批量 ping 的golang 库包

鼎铭 · · 3917 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一个监控项目有个需求,会对一批域名进行探测,这里包括,丢包率,http 响应时间,探测频率大概时间是2min 一个周期。这里的域名大概有几百个,后期可能上千。由于是golang 写的调度和agent, 所以,这里探测丢包率是一个有意思的问题。由于目前git 上没有一个好用的支持batch ping 的库包,参照其他人的实现,我自己实现了一个。

该文章后续仍在不断的更新修改中, 请移步到原文地址http://dmwan.cc, git 地址:https://github.com/caucy/batch_ping

最开始我并不是太明白icmp 协议,我的设想,是有这样几种实现方式。

第一种是最简单的,也是大多数监控agent 采用的方式:subprocess 。这个方式有个缺点,就是每个任务会fork 一个进程,一个是耗费资源,第二个是太慢了;

第二种方式,我是这样想的,golang 有icmp 包,能够支持send and recive, 我直接起协程 去 收发,每个协程和subprocess 一样,先发后等,这样不就行了?然后起一组协程池,这样并发也能控制。然而,too young too simple 。。。

icmp 具体协议不多说,自己百度,主要注意下 id 字段和 seq 字段(大端序和小端序其实是一个字段)就行!下面着重说几个要点。

第二种做法是行不通的,主要是因为这么几个原因:

1, icmp 是ip 层上,tcp/udp 之下 的协议,无连接的,这个大多数人都知道;

2,icmp 是通过原始套接字收发,这个需要root 权限。所以库启动需要授权

3,原始套接字listen ,receive 的时候,是怎么区别是哪个进程发的,哪个进程该收?这个很关键,套接字在收的的时候,是内核直接转发,所有ping 自己机器的包,都能收到。什么意思?自己的进程,需要通过id (自己的进程号)标记这个是自己发出去的,收的时候,grep 掉那些不是自己发的的包。

4, 进程怎么区分,收发的顺序,也就是我到底是第几个包丢了?这个根据seq 可以做到。

那我们到底该怎么做?其实知道上面几点就思路很清晰了,避开不属于自己的包,注意收发顺序,就ok 了。主要实现,是将所有的域名或者ip 解析成ip 后放于一个map 中,一个协程,send icmp ,一个协程 receive icmp, 一个tick 控制时间间隔,一个tick 控制整体超时。最后提供下回调接口就ok。

下面是一个调用示例:

package main
import (
  "batch_ping/ping"
  "time"
  "fmt"
  "golang.org/x/net/icmp"
)
func main (){
  ipSlice := []string{}
  ipSlice = append(ipSlice, "122.228.74.183")
  ipSlice = append(ipSlice, "wwww.baidu.com")
   ipSlice = append(ipSlice, "baidu.com")
  ipSlice = append(ipSlice, "121.42.9.142")
  ipSlice = append(ipSlice, "121.42.9.141")
  ipSlice = append(ipSlice, "121.42.9.144")
  ipSlice = append(ipSlice, "121.42.9.145")
  ipSlice = append(ipSlice, "121.42.9.146")
  ipSlice = append(ipSlice, "121.42.9.147")
  ipSlice = append(ipSlice, "121.42.9.148")
  ipSlice = append(ipSlice, "121.42.9.149")
  ipSlice = append(ipSlice, "121.42.9.150")
  bp, err := ping.NewBatchPinger(ipSlice, 4, time.Second*1, time.Second*10, true)
  if err != nil {
    fmt.Println(err)
  }
  bp.OnRecv = func(pkt *icmp.Echo, srcAddr string) {
    fmt.Printf("recv icmp_id=%d, icmp_seq=%d, srcAddr %v\n",
      pkt.ID, pkt.Seq, srcAddr)
  }
  bp.OnFinish = func(stMap map[string]*ping.Statistics) {
    for ip, st := range stMap{
      fmt.Printf("\n--- %s ping statistics ---\n", st.Addr)
      fmt.Printf("ip %s, %d packets transmitted, %d packets received, %v%% packet loss\n",ip,
        st.PacketsSent, st.PacketsRecv, st.PacketLoss)
      fmt.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
        st.MinRtt, st.AvgRtt, st.MaxRtt, st.StdDevRtt)
    }
  }
  bp.Run()
}

可以做的,还可以支持下ipv6 等等。如果觉得有用点个star,谢谢。


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:鼎铭

查看原文:实现支持批量 ping 的golang 库包

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
3917 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏