Golang实现Ping逻辑


func GetEchoMsg(seq int, data []byte) []byte {
    time_now := time.Now().UnixNano()
    time_data := make([]byte, 8)
    binary.LittleEndian.PutUint64(time_data, uint64(time_now))
    data = append(time_data, data...)
    echo_msg := icmp.Message{
        Type: ipv4.ICMPTypeEcho,
        Code: 0,
        Body: &icmp.Echo{
            ID:   os.Getpid()&0xffff,
            Seq:  seq,
            Data: data,
        },
    }
    echo_data, err := echo_msg.Marshal(nil)
    if err != nil {
        panic(err)
    }
    return echo_data
}

func FilterIP6(addrs []string) ([]string) {
    ret := []string{}
    for _, ip := range addrs {
        if strings.Contains(ip, ":") {
            continue
        }
        ret = append(ret, ip)
    }
    return ret
}

func GetHostAddr(host string) (string, error){
    addrs, err := net.LookupHost(host)
    if err != nil {
        return "", err
    }
    addrs = FilterIP6(addrs)
    addr := addrs[rand.Intn(len(addrs))]
    return addr, nil
}

func PingAddr(host string, seq int, data_size int, timeout time.Duration) (bool, int, error) {
    conn, err := net.DialTimeout("ip4:icmp", host, timeout)
    if err != nil {
        return true, 0, err
    }
    defer conn.Close()
    ping_msg := GetEchoMsg(seq, []byte(strings.Repeat("h", data_size)))
    conn.SetWriteDeadline(time.Now().Add(timeout))
    size, err := conn.Write(ping_msg)
    if err != nil {
        return false, 0, err
    }
    if size != len(ping_msg) {
        return false, 0, errors.New("send ping data err")
    }
    begin_time := time.Now()
    for time.Now().Sub(begin_time) < timeout{
        all_data := make([]byte, 20+size) // ping recv back
        conn.SetReadDeadline(time.Now().Add(timeout))
        _, err := conn.Read(all_data)
        if err != nil {
            return false, 0, err
        }
        header, err := ipv4.ParseHeader(all_data)
        if err != nil {
            return false, 0, err
        }
        var msg *icmp.Message
        msg, err = icmp.ParseMessage(1, all_data[header.Len: header.TotalLen])
        if err != nil {
            return false, 0, nil
        }
        switch msg.Type {
        case ipv4.ICMPTypeEcho:
            continue
        case ipv4.ICMPTypeEchoReply:
            msg.Body.Marshal(1)
            if echo, ok := msg.Body.(*icmp.Echo); !ok {
                return false, 0, errors.New("ping recv err data")
            }else{
                time_now := time.Now().UnixNano()
                send_time := int64(binary.LittleEndian.Uint64(echo.Data[0:8]))
                fmt.Println("ping", host, "data_size", data_size, "ttl", header.TTL, 
                    "icmp_seq",seq, "time", float64(time_now - send_time)/1000000.0, "ms")
                return true, header.TTL, nil
            }
        default:
            continue
        }
    }
    return false, 0, errors.New("ping addr" + host + "timeout")
}

func main() {
    host := flag.String("host", "127.0.0.1", "addr to ping with")
    data_size := flag.Int("size", 64, "data size to ping with")
    flag.Parse()
    addr,err := GetHostAddr(*host)
    if err != nil {
        fmt.Println("ping host", *host, "with err", err)
        return
    }
    for i := 0; i < 10; i++ {
        _, _, err := PingAddr(addr, i, *data_size, 1 * time.Second)
        if err != nil {
            fmt.Println("ping host", addr, "with err", err)
        }
        time.Sleep(1 * time.Second)
    }
}
[root]# go run golang_ping.go -host google.com
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 0 time 0.196331 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 1 time 0.216301 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 2 time 6.050563 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 3 time 6.186337 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 4 time 0.219174 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 5 time 0.210998 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 6 time 0.240042 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 7 time 0.162152 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 8 time 0.168131 ms
ping 172.217.24.14 data_size 64 ttl 37 icmp_seq 9 time 0.211241 ms

讨论请加 QQ group: 549675095


Powered by Jekyll and Theme by solid