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