實現支援批量 ping 的golang 庫包

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

    一個監控項目有個需求,會對一批網域名稱進行探測,這裡包括,丟包率,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 mainimport (    "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,謝謝。

    

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.