Shaw0xyz 发表于 2024-5-18 20:08:38

用Go实现Ping操作

本帖最后由 Shaw0xyz 于 2024-5-18 20:12 编辑

在Go语言中实现一个Ping操作可以通过使用ICMP协议。Go的标准库中没有直接提供Ping操作的库,但可以使用第三方库,例如`golang.org/x/net/icmp`和`golang.org/x/net/ipv4`,来实现。

以下是一个简单的示例,演示如何在Go中实现Ping操作:
package main

import (
    "encoding/binary"
    "fmt"
    "golang.org/x/net/icmp"
    "golang.org/x/net/ipv4"
    "net"
    "os"
    "time"
)

func main() {
    if len(os.Args) != 2 {
      fmt.Printf("Usage: %s <host>\n", os.Args)
      os.Exit(1)
    }

    target := os.Args
    addr, err := net.ResolveIPAddr("ip4", target)
    if err != nil {
      fmt.Printf("Failed to resolve %s: %v\n", target, err)
      os.Exit(1)
    }

    conn, err := net.DialIP("ip4:icmp", nil, addr)
    if err != nil {
      fmt.Printf("Failed to dial: %v\n", err)
      os.Exit(1)
    }
    defer conn.Close()

    // Create ICMP Echo Request packet
    icmpEcho := icmp.Message{
      Type: ipv4.ICMPTypeEcho,
      Code: 0,
      Body: &icmp.Echo{
            ID:   os.Getpid() & 0xffff,
            Seq:1,
            Data: []byte("PING"),
      },
    }

    // Serialize ICMP message
    msg, err := icmpEcho.Marshal(nil)
    if err != nil {
      fmt.Printf("Failed to marshal ICMP message: %v\n", err)
      os.Exit(1)
    }

    // Send ICMP Echo Request
    start := time.Now()
    _, err = conn.Write(msg)
    if err != nil {
      fmt.Printf("Failed to send ICMP message: %v\n", err)
      os.Exit(1)
    }

    // Receive ICMP Echo Reply
    reply := make([]byte, 1500)
    err = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
    if err != nil {
      fmt.Printf("Failed to set read deadline: %v\n", err)
      os.Exit(1)
    }

    n, err := conn.Read(reply)
    if err != nil {
      fmt.Printf("Failed to read ICMP message: %v\n", err)
      os.Exit(1)
    }

    duration := time.Since(start)

    // Parse ICMP message
    parsedMsg, err := icmp.ParseMessage(1, reply[:n])
    if err != nil {
      fmt.Printf("Failed to parse ICMP message: %v\n", err)
      os.Exit(1)
    }

    switch parsedMsg.Type {
    case ipv4.ICMPTypeEchoReply:
      echoReply, ok := parsedMsg.Body.(*icmp.Echo)
      if !ok {
            fmt.Println("Received unexpected ICMP message body")
            os.Exit(1)
      }
      fmt.Printf("Received ICMP Echo Reply from %s: id=%d seq=%d time=%v\n", addr, echoReply.ID, echoReply.Seq, duration)
    default:
      fmt.Printf("Received unexpected ICMP message type %v\n", parsedMsg.Type)
    }
}


运行此代码的步骤:

1. 安装依赖包:
    go get golang.org/x/net/icmp
    go get golang.org/x/net/ipv4

2. 保存代码到一个文件,如`ping.go`。

3. 运行代码:
    go run ping.go example.com

代码说明:

1. 解析目标地址:通过`net.ResolveIPAddr`解析目标主机的IP地址。
2. 建立连接:使用`net.DialIP`建立到目标主机的ICMP连接。
3. 构造ICMP请求:创建一个ICMP Echo Request消息,并将其序列化为字节数组。
4. 发送请求:通过连接发送ICMP Echo Request。
5. 接收响应:读取从目标主机返回的ICMP Echo Reply,并解析响应消息。
6. 显示结果:显示响应的详细信息,包括响应时间。

这个示例演示了如何使用Go语言进行Ping操作,通过发送ICMP Echo Request并接收Echo Reply来测量目标主机的响应时间。
页: [1]
查看完整版本: 用Go实现Ping操作