使用golang实现ping功能
func ping(ip string) error {
// 解析目标 IP 地址
dst, err := net.ResolveIPAddr("ip4", ip)
if err != nil {
return fmt.Errorf("解析 IP 地址失败: %w", err)
}
// 创建 ICMP 连接
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
return fmt.Errorf("无法创建 ICMP 连接: %w", err)
}
defer conn.Close()
// 构造 ICMP Echo 请求
msg := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff, // ICMP ID 可以使用进程 ID
Seq: 1,
Data: []byte("HELLO-R-U-THERE"),
},
}
// 序列化 ICMP 请求
msgBytes, err := msg.Marshal(nil)
if err != nil {
return fmt.Errorf("ICMP 请求序列化失败: %w", err)
}
// 设置超时时间
if err := conn.SetDeadline(time.Now().Add(2 * time.Second)); err != nil {
return fmt.Errorf("设置超时失败: %w", err)
}
// 发送 ICMP 请求到目标 IP
_, err = conn.WriteTo(msgBytes, dst)
if err != nil {
return fmt.Errorf("发送 ICMP 请求失败: %w", err)
}
// 接收 ICMP 响应
reply := make([]byte, 1500)
n, _, err := conn.ReadFrom(reply)
if err != nil {
return fmt.Errorf("接收 ICMP 响应失败: %w", err)
}
// 解析 ICMP 响应
resp, err := icmp.ParseMessage(ipv4.ICMPTypeEcho.Protocol(), reply[:n])
if err != nil {
return fmt.Errorf("解析 ICMP 响应失败: %w", err)
}
// 检查响应类型是否为 Echo Reply
if resp.Type == ipv4.ICMPTypeEchoReply {
return nil
}
return fmt.Errorf("非预期的 ICMP 响应: %v", resp)
}