-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
139 lines (127 loc) · 3.13 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"bytes"
"encoding/binary"
"flag"
"fmt"
"log"
"math"
"net"
"os"
"time"
)
var (
timeout int64
size int
count int
typ uint8 = 8
code uint8 = 0
sendCount int
successCount int
failCount int
minTimeUse int64 = math.MaxInt32
maxTimeUse int64
totalTimeUse int64
)
// ICMP 定义头部信息
type ICMP struct {
Type uint8
Code uint8
CheckSum uint16
ID uint16
SequenceNum uint16
}
func main() {
getCommandArgs()
// 目标IP地址,取命令行最后一个参数
targetIp := os.Args[len(os.Args)-1]
// 创建一个连接
conn, err := net.DialTimeout("ip:icmp", targetIp, time.Duration(timeout)*time.Millisecond)
if err != nil {
log.Fatal(err)
return
}
// 关闭连接
defer func(conn net.Conn) {
_ = conn.Close()
}(conn)
fmt.Printf("正在 Ping %s [%s] 具有 %d 字节的数据:\n", targetIp, conn.RemoteAddr(), size)
for i := 0; i < count; i++ {
sendCount++
icmp := &ICMP{
Type: typ,
Code: code,
CheckSum: 0,
ID: 1,
SequenceNum: 1,
}
data := make([]byte, size)
var buffer bytes.Buffer
timeStart := time.Now()
_ = binary.Write(&buffer, binary.BigEndian, icmp)
buffer.Write(data)
data = buffer.Bytes()
checkSum := checkSum(data)
// 高8位
data[2] = byte(checkSum >> 8)
// 低8位
data[3] = byte(checkSum)
_ = conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond))
n, err := conn.Write(data)
if err != nil {
failCount++
log.Println(err)
continue
}
buf := make([]byte, 65535)
n, err = conn.Read(buf)
if err != nil {
failCount++
log.Println(err)
continue
}
successCount++
timeUse := time.Since(timeStart).Milliseconds()
if minTimeUse > timeUse {
minTimeUse = timeUse
}
if maxTimeUse < timeUse {
maxTimeUse = timeUse
}
totalTimeUse += timeUse
fmt.Printf("来自 %d.%d.%d.%d 的回复: 字节=%d 时间=%d ms TTL=%d\n",
buf[12], buf[13], buf[14], buf[15], n-28, timeUse, buf[8])
time.Sleep(time.Second)
}
fmt.Printf("%s 的 Ping 统计信息: \n"+
" 数据包: 已发送 = %d,已接收 = %d,丢失 = %d (%.2f%% 丢失),\n"+
"往返行程的估计时间(以毫秒为单位): \n "+
"最短 = %dms,最长 = %dms,平均 = %dms ",
conn.RemoteAddr(), sendCount, successCount, failCount, float64(failCount)/float64(sendCount)*100, minTimeUse, maxTimeUse, totalTimeUse/int64(sendCount))
}
// getCommandArgs 获取命令行的参数
func getCommandArgs() {
flag.Int64Var(&timeout, "w", 1000, "请求超时时长,单位毫秒")
flag.IntVar(&size, "l", 32, "请求发送缓冲区大小,单位字节")
flag.IntVar(&count, "n", 4, "发送请求数")
flag.Parse()
}
func checkSum(data []byte) uint16 {
length := len(data)
index := 0
var sum uint32 = 0
for length > 1 {
sum += uint32(data[index])<<8 + uint32(data[index+1])
length -= 2
index += 2
}
if length != 0 {
sum += uint32(data[index])
}
highOrder16 := sum >> 16
for highOrder16 != 0 {
sum = highOrder16 + uint32(uint16(sum))
highOrder16 = sum >> 16
}
return uint16(^sum)
}