golang实现ping命令(附:完整代码)

golang实现ping命令(附:完整代码)

ziyi首先在这里祝大家新春快乐,龙年大吉,🐲行大运呀!,下面开始进入正题:

代码:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/ping_demo

1 ping原理:ICMP协议(Type+Code+checksum+ID+sequence)

ping是使用ICMP协议。ICMP协议的组成:

  • Type(8bits) + Code(8bits) + 校验码(checksum,8bits) + ID(16bits) + 序号(sequence,16bits) + 数据
    在这里插入图片描述

这些组成部分的含义:
1)Type: ICMP的类型,标识生成的错误报文
2)Code: 进一步划分ICMP的类型,该字段用来查找产生的原因;例如,ICMP的目标不可达类型可以把这个位设为1至15等来表示不同的意思。

在这里插入图片描述

总结:ICMP协议的组成:Type(8bits) + Code(8bits) + 校验码(checksum,8bits) + ID(16bits) + 序号(sequence,16bits) + 数据

这些组成部分的含义:
1)Type ICMP的类型,标识生成的错误报文
2)Code 进一步划分ICMP的类型,该字段用来查找产生的原因;例如,ICMP的目标不可达类型可以把这个位设为1至15等来表示不同的意思。
3)CheckSum 校验码部分,这个字段包含从ICMP报头和数据部分计算得来的,用于检查错误的,其中此校验码字段的值视为0.
4)ID 这个字段包含了ID值,在Echo Reply类型的消息中要返回这个字段。
5)Sequence 这个字段包含一个序号

ping命令的实现是使用ICMP中类型值为8(reply)和0(request)

1.1 Type 类型值,标识ICMP分组类型

1.2 Code 代码值,标识ICMP分组类型的某一种具体分组

1.3 Checksum 校验和,用于检验数据包是否完整或是否被修改

1.4 Identifier 标识符,标识本进程。当同时与多个目的通信时,通过本字段来区分

1.5 Sequence Number 序列号,标识本地到目的的数据包序号,一般从序号1开始

常见ICMP类型

  • 回复应答(ICMP类型0):ping命令用到该类型的数据包以测试TCP/IP连接;
  • 目标不可达 (ICMP类型3):用以知识目标网络、主机或者端口不可达;
  • 源站抑制 (ICMP类型4):当路由器处理IP数据的速度不够快时,会发送此类的消息。它的意思是让发送方降低发送数据的速率。Microsoft Windows NT或Windows 2000主机可以通过降低数据传输率来响应这种类型的消息;
  • 重定向消息 (ICMP类型5):用于将主机重新定向到一个不同的网络路径,该消息告诉路由器对于该数据包可以忽略它内部的路由表项;
    回复请求(ICMP类型8):ping命令用该类型的数据包测试TCP/IP连接;
  • 路由器通告 (ICMP类型9):以随机的时间间隔发送该数据包以响应
  • 路由器请求 (ICMP类型10):路由器发送该数据包来请求路由器通告的更新;
  • 超时 (ICMP类型11):指示数据包由于通过了太多的网段,其的生存时间(TTL)已经过期,Tracert命令用此消息来测试本地和远程主机之间的多个路由器;
  • 参数问题 (ICMP类型12):用以指示处理IP数据包头时出错。

2 实现

2.1 定义ICMP结构体

type ICMP struct {
   
   
    Type        uint8
    Code        uint8
    Checksum    uint16
    Identifier  uint16
    SequenceNum uint16
}

2.2 计算校验和

官网解释:The checksum is the 16-bit ones’s complement of the one’s
complement sum of the ICMP message starting with the ICMP Type.
For computing the checksum , the checksum field should be zero.
If the total length is odd, the received data is padded with one
octet of zeros for computing the checksum. This checksum may be
replaced in the future.

  1. 获取ICMP报文(首部+数据部分)
  2. 将ICMP报文中的校验和字段置为0。
  3. 将ICMP协议报文中的每两个字节(16位,需要注意大小端问题)两两相加,得到一个累加和。若报文长度为奇数,则最后一个字节(8-bit)作为高8位,再用0填充一个字节(低8-bit)扩展到16-bit,之后再和前面的累加和继续相加得到一个新的累加和。
  4. (若有溢出)将累加和的高16位和低16位相加,直到最后只剩下16位。
func CheckSum(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 = uint16(sum >> 16) + uint16(sum)
        sum = uint16(sum >> 16) + uint16(sum)
    return uint16(^sum)
}

2.3 命令行参数

var (
    icmp  ICMP
    laddr = net.IPAddr{
   
   IP: net.ParseIP("ip")}
    num     int
    timeout int64
    size    int
    stop    bool
)

func ParseArgs() {
   
   
    flag.Int64Var(&timeout, "w", 1500, "等待每次回复的超时时间(毫秒)")
    flag.IntVar(&num, "n", 4, "要发送的请求数")
    flag.IntVar(&size, "l", 32, "要发送缓冲区大小")
    flag.BoolVar(&stop, "t", false, "Ping 指定的主机,直到停止")

    flag.Parse()
}

func Usage() {
   
   
    argNum := 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值