手写的 Go ping 实现
用 Go 手写一个 Ping 工具
引言
简介 Ping 工具的历史和作用
说明实现该工具的目的
ICMP 协议简介
ICMP 的基本概念
ICMP 报文结构
Ping 的工作原理
Go 语言与网络编程
Go 的网络编程基础
使用 net 和 golang.org/x/net/icmp 包
实现细节
解析命令行参数
创建 ICMP 连接
发送和接收 ICMP 报文
发送 Echo 请求
接收 Echo 回复
计算往返时间 (RTT)
代码解析
逐行讲解 ping.go 的实现
关键函数的详细说明
运行与测试
如何运行程序
常见错误及解决方法
结果分析与输出示例
扩展与优化
如何增加并发支持
添加更多功能,例如自定义包大小、TTL 等
处理不同操作系统的兼容性
总结
重申 Ping 工具的重要性
鼓励读者探索 Go 语言的网络编程
package main
import (
“fmt”
“net”
“os”
“time”
“golang.org/x/net/icmp”
“golang.org/x/net/ipv4”
)
const (
icmpTypeEchoRequest = 8
icmpTypeEchoReply = 0
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run ping.go <host>")
return
}
host := os.Args[1]
address, err := net.ResolveIPAddr("ip", host)
if err != nil {
fmt.Println("ResolveIPAddr failed:", err)
return
}
conn, err := net.DialIP("ip4:icmp", nil, address)
if err != nil {
fmt.Println("DialIP failed:", err)
return
}
defer conn.Close()
for i := 0; i < 4; i++ {
start := time.Now()
err = sendICMP(conn, address)
if err != nil {
fmt.Println("Send failed:", err)
return
}
err = receiveICMP(conn)
if err != nil {
fmt.Println("Receive failed:", err)
return
}
rtt := time.Since(start)
fmt.Printf("Reply from %s: bytes=32 time=%v\n", host, rtt)
time.Sleep(1 * time.Second)
}
}
func sendICMP(conn *net.IPConn, address *net.IPAddr) error {
msg := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{Seq: 1, ID: 1, Data: []byte(“HELLO”)},
}
data, err := msg.Marshal(nil)
if err != nil {
return err
}
_, err = conn.WriteTo(data, address)
return err
}
func receiveICMP(conn *net.IPConn) error {
buf := make([]byte, 1500)
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
_, _, err := conn.ReadFrom(buf)
return err
}
- 点赞
- 收藏
- 关注作者
评论(0)