1 Star 0 Fork 0

leminewx / gokit

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
icmp.go 4.95 KB
一键复制 编辑 原始数据 按行查看 历史
package protocol
import (
"bytes"
"encoding/binary"
"fmt"
"math"
"net"
"time"
)
// ICMP 定义 ICMP 协议包头
type ICMP struct {
Type uint8 // 类型
Code uint8 // 代码
Checksum uint16 // 校验和
Identifier uint16 // 标识符
SequenceNum uint16 // 序列号
}
const (
_ICMP_TIMEOUT = 100
_ICMP_DATA_SIZE = 32
)
// Ping 执行 ping 命令,并实时打印网络状态
func Ping(ip string, num int) (float64, error) {
// 创建 ICMP 连接
conn, err := net.DialTimeout("ip:icmp", ip, time.Duration(_ICMP_TIMEOUT)*time.Millisecond)
if err != nil {
return 100.0, err
}
defer conn.Close()
// 创建 ICMP 数据包
icmp := ICMP{
Type: 8,
Identifier: 1,
SequenceNum: 1,
}
// 写入 ICMP 数据到 buffer
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, icmp) // 以大端模式写入(低位对应高地址)
buffer.Write(make([]byte, _ICMP_DATA_SIZE))
data := buffer.Bytes()
var successTimes int // 成功次数
var failTimes int // 失败次数
var minTime = math.MaxInt32 // 单次最短时间
var maxTime int // 单次最长时间
var totalTime int // 累积执行时间
fmt.Printf("\n正在 ping %s 具有 %d 字节的数据:\n", ip, _ICMP_DATA_SIZE)
for i := 0; i < num; i++ {
icmp.SequenceNum = uint16(1)
// 检验和设为0
data[2] = byte(0)
data[3] = byte(0)
data[6] = byte(icmp.SequenceNum >> 8)
data[7] = byte(icmp.SequenceNum)
// 设置 checksum
icmp.Checksum = checkICMPSum(data)
data[2] = byte(icmp.Checksum >> 8)
data[3] = byte(icmp.Checksum)
// 开始时间
t1 := time.Now()
conn.SetDeadline(t1.Add(time.Duration(_ICMP_TIMEOUT) * time.Millisecond))
// 设置 icmp 包 checksum 校验和
if _, err := conn.Write(data); err != nil {
return 100.0, err
}
buf := make([]byte, 65535)
n, err := conn.Read(buf)
if err != nil {
fmt.Println("请求超时。")
failTimes++
continue
}
//time.Now()转换为毫秒
et := int(time.Since(t1) / 1000000)
if minTime > et {
minTime = et
}
if maxTime < et {
maxTime = et
}
totalTime += et
successTimes++
fmt.Printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%d\n", ip, len(buf[28:n]), et, buf[8])
time.Sleep(1 * time.Second)
}
fmt.Printf("\n%s 的 Ping 统计信息:\n", ip)
fmt.Printf(" 数据包: 已发送 = %d,已接收 = %d,丢失 = %d (%.2f%% 丢失),\n", successTimes+failTimes, successTimes, failTimes, float64(failTimes*100)/float64(successTimes+failTimes))
if maxTime != 0 && minTime != math.MaxInt32 {
fmt.Printf("往返行程的估计时间(以毫秒为单位):\n")
fmt.Printf(" 最短 = %dms,最长 = %dms,平均 = %dms\n", minTime, maxTime, totalTime/successTimes)
}
return float64(failTimes) / float64(successTimes+failTimes), nil
}
// Ping 执行 ping 命令,不打印网络状态
func PingWithoutPrint(ip string, num int) (float64, error) {
// 创建 ICMP 连接
conn, err := net.DialTimeout("ip:icmp", ip, time.Duration(_ICMP_TIMEOUT)*time.Millisecond)
if err != nil {
return 100.0, err
}
defer conn.Close()
// 创建 ICMP 数据包
icmp := ICMP{
Type: 8,
Identifier: 1,
SequenceNum: 1,
}
// 写入 ICMP 数据到 buffer
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, icmp) // 以大端模式写入(低位对应高地址)
buffer.Write(make([]byte, _ICMP_DATA_SIZE))
data := buffer.Bytes()
var successTimes int // 成功次数
var failTimes int // 失败次数
var minTime = math.MaxInt32 // 单次最短时间
var maxTime int // 单次最长时间
var totalTime int // 累积执行时间
for i := 0; i < num; i++ {
icmp.SequenceNum = uint16(1)
// 检验和设为0
data[2] = byte(0)
data[3] = byte(0)
data[6] = byte(icmp.SequenceNum >> 8)
data[7] = byte(icmp.SequenceNum)
// 设置 checksum
icmp.Checksum = checkICMPSum(data)
data[2] = byte(icmp.Checksum >> 8)
data[3] = byte(icmp.Checksum)
// 开始时间
t1 := time.Now()
conn.SetDeadline(t1.Add(time.Duration(_ICMP_TIMEOUT) * time.Millisecond))
// 设置 icmp 包 checksum 校验和
if _, err := conn.Write(data); err != nil {
return 100.0, err
}
buf := make([]byte, 65535)
if _, err := conn.Read(buf); err != nil {
failTimes++
continue
}
//time.Now()转换为毫秒
et := int(time.Since(t1) / 1000000)
if minTime > et {
minTime = et
}
if maxTime < et {
maxTime = et
}
totalTime += et
successTimes++
time.Sleep(1 * time.Second)
}
return float64(failTimes) / float64(successTimes+failTimes), nil
}
// checkICMPSum 计算校验和
func checkICMPSum(data []byte) uint16 {
var sum uint32
var length = len(data)
var index int
for length > 1 { // 溢出部分直接去除
sum += uint32(data[index])<<8 + uint32(data[index+1])
index += 2
length -= 2
}
if length == 1 {
sum += uint32(data[index])
}
sum = uint32(uint16(sum>>16) + uint16(sum))
sum = uint32(uint16(sum>>16) + uint16(sum))
return uint16(^sum)
}
Go
1
https://gitee.com/leminewx/gokit.git
git@gitee.com:leminewx/gokit.git
leminewx
gokit
gokit
9c69314efcfa

搜索帮助

53164aa7 5694891 3bd8fe86 5694891