手把手教你用Go实现Ping操作
这次我们来看一下什么是 Ping 操作,以及它有什么用处,并且我们来动手实现一个简易版的 Ping 工具。
Ping 是什么?
ping
是一个计算机网络工具,通常用于测试网络连接的可达性和测量往返时间。在大多数操作系统中,ping
命令是一个内置的命令行工具,可以通过命令行终端使用。例如,在 Windows 操作系统中,你可以在命令提示符中运行 ping
命令,而在类 Unix 操作系统(如 Linux 和 macOS)中,你可以在终端中使用 ping
命令。通常,命令的语法是 ping 目标主机或 IP
,然后命令将输出与目标主机的通信状态和 RTT 相关的信息。
Ping 有什么用处?
Ping
工具主要有以下几个主要用途:
- 测试主机的可达性:
ping
命令用于检查另一个主机是否可以在网络上访问。它向目标主机发送一个小的数据包(通常是 ICMP Echo Request),如果目标主机正常工作,它将响应一个回复数据包(通常是 ICMP Echo Reply)。如果没有响应,那么目标主机可能无法访问或处于离线状态。 - 测量往返时间(RTT):
ping
命令通常会显示每次请求和响应之间的时间差,这被称为往返时间(RTT)。这个值表示了数据从发送端到接收端的往返延迟,通常以毫秒为单位。测量 RTT 对于评估网络性能和延迟非常有用。 - 网络故障排除:
ping
是网络故障排除的有用工具之一。通过检查ping
的输出,网络管理员可以确定网络连接是否正常,以及延迟是否在可接受范围内。如果ping
失败,管理员可以进一步调查网络故障的原因。 - 监测网络稳定性:
ping
命令还可以用于监测网络的稳定性。通过连续地向目标主机发送ping
请求,可以了解网络连接的质量和稳定性。如果出现不稳定性,管理员可以及时采取措施。
动手实现一个 Ping 工具
首先,我们要了解一下 Ping
操作的工作原理:向网络上的另一个主机系统发送 ICMP
报文,如果指定系统得到了报文,它将把回复报文传回给发送者。
先来看看 ICMP 报文长什么样:
ICMP 报文由 ICMP 报文头 和 数据包组成,其报文头包含 Type、Code、Checksum、ID、SequenceNum 字段。因此,我们需要先在本地主机上定义 ICMP 请求报文结构体:
1 |
|
上面只是 ICMP 的报文头,我们在后面还需要为这个报文构建请求数据。需要注意的是,定义的顺序不能乱,因为我们发送数据包是按字节发送的,所以获取对应的字段的时候,也是按照对应字段的位置去获取的,如果顺序乱了,获取到的数据就会出错。
在构建数据之前,我们先设置好命令行参数,以获取对应参数和目标 IP,同时需要定义全局变量,将命令行参数绑定到对应的变量中,方便使用:
1 |
|
在 main
函数中,启用命令行参数设置:
1 |
|
在发送报文前,我们需要先建立连接,此时需要先获取目标 IP,这个由命令行参数中获取:
1 |
|
连接建立后,我们需要根据参数中的发送次数 count
去发送对应次数的报文,因此需要用 for
去做:
1 |
|
通过百度百科可以查到,我们要使用的是 Ping 请求,即回显请求,其对应的 Type 和 Code 如下:
同样,我们在全局变量中添加对应的值:
1 |
|
做好前面的准备工作,我们就可以开始构建我们的 ICMP 请求报文了。我们这里以发送的第几次作为 ID 和序列号:
1 |
|
由于 ICMP 是使用二进制进行传输的,所以我们需要将信息用二进制表示:
1 |
|
然后根据发送数据的大小 size
构建数据并写在 ICMP 报文后面:
1 |
|
现在,就只差一个校验和字段了,计算 ICMP(Internet Control Message Protocol)报文的校验和字段遵循以下步骤:
- 将报文分为 16 位的字(两个字节)。
- 对所有字进行按位求和(二进制求和),包括数据部分和报文头。如果有剩余字节(奇数个字节),将其附加到最后一个字节。
- 将溢出的进位位(如果有)加回到结果中。
- 取结果的二进制反码(按位取反)
代码实现如下:
1 |
|
接着再将算出来的校验和放到报文头对应的位置中去,这里需要计算一下位置。假设我们有以下 ICMP 报文:
1 |
|
校验和属于报文的第3、4个字节,即 data[2] 和 data[3]。
1 |
|
最后再设置一下超时时间,就可以将数据 data
写入连接中了:
1 |
|
发送完成后,再构建缓冲接收响应包,
1 |
|
然后我们就可以从响应包中获取我们需要的数据,比如 IP 地址、TTL等:
根据抓到的 ICMP 响应包,可以知道 IP 头共 20 个字节,源 IP 和 目标 IP 在我们接收的数据包的倒数 8 个字节里,所以我们可以推算出我们访问的 IP 地址,就可以构建我们的打印信息了:
1 |
|
至此,我们 Ping 工具的核心功能就实现了,还有一些统计信息,就不做具体的讲解了,感兴趣的可以从代码中看具体的实现。
完整代码如下:
1 |
|
小结
本文讲解了常用工具 Ping,并且从 ICMP 报文角度手把手教大家实现了一个简易版的 Ping 工具,在这个过程中大家可以收获到很多东西,希望大家能够自己动手实现一下,结果一定不会让你失望。