搞了运维开发这么多年,原来 Ping 还能这么玩儿

article/2025/9/16 11:59:05

作者:刘勇

腾讯后台研发工程师,就读于北京大学。目前主要从事腾讯云-云拨测项目后台开发相关工作。

网络:良辰有一百种方法让你 Ping 不通,你却无可奈何

为什么 Ping 不通了?为什么又通了?

这些居然都能 Ping 通?

这似乎是每个开发或运维会经常面对的灵魂拷问。

而关于 Ping 你又了解多少?知道 Ping 还能这么玩吗?

Ping 的含义-两端的连通性

在开发和运维中我们时常要关心一类问题,客户端和服务器是否可以通信,业务服务能否连接到数据库等两端连通性问题。最常用到的手段就是对目标网络执行 Ping 命令,通过向目标机器发送请求数据并接收回应数据来确认是否存在丢包等网络不畅通的情况。

在网络架构日益复杂的情况下,Ping 的身影无处不在,举几个例子:如图所示,在 WLAN 下为了确认主机是否与路由器联通,主机会定时向路由地址发送数据并接收路由器的响应(如图中每2秒进行一次探测);比如在使用 Redis 时,可以通过输入 “ping” 检查是否与该 Redis 连接成功,如果连接正常就会回复一个"pong";

同样在使用数据库时也有类似的 Ping 操作来确认连接;再比如网游中的 Ping时延也是通过定时 Ping 游戏服务器得到的延迟数据。谈到网络协议就不得不提到计算机网络中的分层模型,一般的网络分层模型中,Ping 操作处于 IP 层/网络层,但是基于 Ping 操作的理念(即确认两端的连通性并不局限在网络层),在传输层甚至应用层都有其不同的实现和应用。

接下来,我们就依照从网络层到传输层再到应用层的顺序,来详细讲解一下 Ping 的实现原理以及拓展的 Ping 的形式。

图片

在讲解具体的 Ping 协议内容之前,我们先来看一下百科中 Ping 的标准定义:Ping 的全称是 Packet Internet Groper,即分组间包探测,是一种因特网包探索器,用于测试网络连通性的检查。我们仔细看一下 Ping 的英文全称——Packet Internet Groper,大家有没有觉得很奇怪,为什么 Ping 的英文不是像DNS(Domain Name Serve)这样的首字母缩写,而是并不与英文完全对应,还用到了 groper 这样并不标准化的词语?

实际上 Ping 的英文全称是后来人们”生搬硬套“上去的。回顾 Ping 的历史,第一个开发出 Unix 中 Ping 程序的美国程序员 Mike Muuss,在他的 “The Story of the PING Program(Ping 程序的故事)” 这篇文章中提到,他是根据声呐探测和回声定位中的 Ping 协议为这个 Ping 程序命名的,因为在这个程序的过程与声呐探测有着异曲同工之妙。主动声呐中发出的声波称为 Ping,而对应的回声称为 pong。而网络探测中主动探测方发出的请求称为 Ping,接受者的回应称为 pong。

图片

Ping 的实质就是用类似打招呼的方式来确认双发的通信状况,只不过在互联网世界中由于网络状况复杂,很容易出现打招呼对方接收不到的情况,即丢包的情况出现。这个时候,我们光知道通信不了这个现实没有什么用,重要的是要知道丢包的具体原因,是网络拥堵导致丢包,还是对端机器出现故障,又或是其他原因。这就涉及到 Ping 的又一大功能——通过协议内容的错误信息来确认丢包的具体原因。我们就先从最基本的网络层层面的 ICMP 协议 Ping 讲起。

ICMP 协议- Ping

ICMP (Internet Control Message Protocol 因特网报文控制协议)主要的功能包括:确认IP包是否成功送达目标地址、报告发送过程中IP包被废弃的原因和改善网络设置等。在 IP 通信中如果某个 IP 包因为某种原因未能达到目标地址,那么这个具体的原因将由 ICMP 负责通知。所以 ICMP 在网络分层中与 IP 层处于同一层,用于传递 IP 报文的控制信息。

在协议名字中有一个很关键的词——控制。网络包在复杂的网络传输环境里,常常会遇到各种问题。咱们并不怕遇到问题,怕的是不知道问题产生的原因,就像线上发现 bug 查询监控日志一样,我们需要一种控制手段来确定网络不通问题出错的点,是本地网络不通还是对端网络问题,或是对方网络根本不存在。在网络层要确定错误原因我们就需要传出消息,从回显的报告中获知遇到了什么问题,这样才可以调整传输策略,以此来控制整个局面。下面以 ICMP -Ping 目标不可达为例子来说明一下 ICMP-Ping 的过程:

图片

主机 A 向主机 B 发送了数据包,途中的路由器 2 时,根据ARP协议映射表中未能发现主机 B 的IP与MAC地址的映射(因为此时B已经关机),这种情况下路由器 2 就会向主机 A 发送一个 ICMP 目标不可达数据包,说明发往主机 B 的包未能成功。

ICMP 的这种通知消息会使用 IP 进行发送 。因此,从路由器 2 返回的 ICMP 包会按照往常的路由控制先经过路由器 1 再转发给主机 A 。收到该 ICMP 包的主机 A 则分解 ICMP 的首部和数据域以后得知具体发生问题的原因。

除了不可达信息,其实ICMP报文中了多种错误方式:

1. Request timed out

请求超时,这是大家经常碰到的提示信息,导致ICMP超时的情况至少有下几种:

  • 网络上不存在目标地址。

  • 对方与自己不在同一网段内,通过路由也无法找到对方。

  • 对方确实存在,但设置了 ICMP 数据包过滤(比如防火墙设置)。

  • 错误设置 IP 地址:正常情况下,一台主机应该有一个网卡,一个 IP 地址,或多个网卡,多个 IP 地址(这些地址一定要处于不同的IP子网)。但如果一台电脑的“拨号网络适配器”(相当于一块软网卡)的 TCP/IP 设置中,设置了一个与网卡 IP 地址处于同一子网的 IP 地址,这样,在 IP 层协议看来,这台主机就有两个不同的接口处于同一网段内。

    当从这台主机 Ping 其他的机器时,会存在这样的问题:

    1. 主机不知道将数据包发到哪个网络接口,因为有两个网络接口都连接在同一网段。

    2. 主机不知道用哪个地址作为数据包的源地址。

    因此,从这台主机去Ping其他机器,IP 层协议会无法处理,超时后,Ping 就会给出一个“超时无应答”的错误信息提示。但从其他主机 Ping 这台主机时,请求包从特定的网卡来,ICMP 只须简单地将目的、源地址互换,并更改一些标志即可,ICMP 应答包能顺利发出,其他主机也就能成功 Ping 通这台机器了。

2. Destination host Unreachable

  • 对方与自己不在同一网段内,而自己又未设置默认的路由,比如上例中 A 机中不设定默认的路由,运行 Ping 192.168.0.1.4 就会出现“Destination host Unreachable”。

  • 链路层出现故障

这里要说明一下“destination host unreachable”和 “time out”的区别,如果所经过的路由器的路由表中具有到达目标的路由,而目标因为其他原因不可到达,这时候会出现“time out”,如果路由表中连到达目标的路由都没有,那就会出现“destination host unreachable”。

3.Bad IP address

这个信息表示您可能没有连接到DNS服务器,所以无法解析这个IP地址,也可能是IP地址不存在。

4.Source quench received

这个信息比较特殊,它出现的机率很少。它表示对方或中途的服务器繁忙无法回应。

5.Unknown host——不知名主机

这种出错信息的意思是,该远程主机的名字不能被域名服务器(DNS)转换成IP地址。故障原因可能是域名服务器有故障,或者其名字不正确,或者网络管理员的系统与远程主机之间的通信线路有故障。

6.No answer——无响应

这种故障说明本地系统有一条通向中心主机的路由,但却接收不到它发给该中心主机的任何信息。故障原因可能是下列之一:中心主机没有工作;本地或中心主机网络配置不正确;本地或中心的路由器没有工作;通信线路有故障;中心主机存在路由选择问题。

7.Ping 127.0.0.1

127.0.0.1是本地循环地址,如果本地址无法 Ping 通,则表明本地机 TCP/IP 协议不能正常工作。

8.no rout to host

网卡工作不正常。

9.unknown host name

DNS 配置不正确。

**拓展的 Ping 操作
**

ICMP-Ping只是 Ping 的一种最常用的形式,实际上检测两端的连通性并不一定要用到 ICMP 协议。在网络分层模型中,我们知道 ICMP 协议工作在网络层,而建立两端的主机通信就是在网络层,所以采用网络层的 ICMP 进行连通性检测理所应当。

不过在分层模型中我们也知道传输层和应用层协议依赖着网络层,TCP、UDP 协议要依靠 IP 协议进行传输,HTTP 协议依赖 TCP 协议通过握手建立连接后通信。所以网络层可达是其上层协议成功的必要非充分条件。所以我们也可以通过 TCP,UDP 协议进行 Ping 操作。下面我们就详细说一下使用 TCP、UDP 协议进行 Ping 的原理和流程。

1. TCPPing

在 TCP 协议中,SYN 包用来表示建立连接请求。如果对方端口处在 listening状态,就会回送 ACK 包,并附上自己的 ISN。但是如果对方端口是关闭的,它会发回一个 RST 包,表示应该马上断开连接(少数情况下会发回一个同时置 SYN 和 ACK 位的包)。

如果我们向一个端口发送 ACK 包,而事先没有与此端口建立连接,那么,无论端口是否打开,它都会回送一个 RST 包。所以可以看出,无论这个端口是否打开,总会有某一种数据包返回,以此可以判定目标主机可达。而目标主机如果不可达,路由器就会向扫描主机发送目的地不可达的ICMP 报文。

这样,通过向目标主机发送 TCPSYN 包或 TCPACK 包就可以准确判断目标主机是否可达,而且根据 RFC793(TCP),目标主机(或路由器)都无法屏蔽 TCPSYN 包和 TCPACK 包,因此,TCP-Ping 的准确性比 ICMP-Ping 的准确性要高。但要注意的是:与 ICMP 协议不同。

使用 TCPing 的时候必须要指定目标主机的端口,如果该端口开启了 TCP 服务,则连接建立成功,表示两端可以正常连通。如果没有开启该端口的 TCP 服务,则会收到该主机发送的 RST 标志位置1的 TCP 包,此时也表示两端可以连通。但是当两端不连通的时候,TCP请求会一直重传(TCP Retransmission),超过超时时间就可认为两端不连通。

如图所示,本机的 6901 端口没有开启 TCP 服务,对 6901 端口建立连接时收到 RST 报文。

图片

图片

2. UDP-Ping:

UDP-Ping 与 TCP-Ping的原理类似,在发包时指定一个数量值很大的目的端口号,很少应用程序用到数量值入的端口号,也就是说该端口很有可能是处于关闭状态。首先构建好 UDP 报文,然后递交给网络层发送。如果目标主机不可达(网络不通或主机未打开),则路由器将发送一个目的不可达 ICMP 报文。而如果目标主机可达,在其接收数据时,其 UDP 实体首先判断接收到的目的端口号是否与当前使用的某端口号匹配,如果匹配,则将数据报放入到对应的接收队列,否则如果目的端口号对应的端口关闭则丢弃该数据报,并回送一个“端口不可达”的 ICMP 报文。

因此,只要目标主机可达,UDPPing 程序将收到一个 UDP 回应包(也可能没有)或者“端口不可达”的ICMP报 文而目标主机不可达,将收到“目的不可达”的 ICMP报文 。如图所示对本机的 8892 端口发送 UDP 报文,但是8892号端口没有开启 UDP 服务,收到端口不可达的 ICMP 报文。

图片

图片

事实上在 UDP 协议设计之初就考虑到了端口不可达的情况,如果收到一份 UDP 数据报而目的端口与某个正在使用的进程不相符,那么 UDP 返回一个 ICMP 不可达报文。虽然是发送的 UDP 协议的报文,但回包却是 ICMP 协议的报文,这似乎违背了网络分层的初衷。在网络通信中讲究”身份对等“的原则,即每一个分层做的事情在发送端和接收端是对等的。

比如发送端用UDP协议发送数据,首先数据要先经过传输层加上 UDP 报文头部,传输到网卡出口时加上网络层的 IP 协议报文头部,随后进入链路层由 ARP 地址解析协议选择路由下一跳,而发送端添加的协议头部内容只会由接收端的对应网络层和传输层进行解析。

回到我们 UDP-Ping 的例子,在这里我们发送 UDP 报文,但是却由ICMP这个网络层的协议返回结果,是不是违反了这个”身份对等“的原则?仔细思考一下其实因为目标端口没有开启 UDP 服务,该数据就还没有进入传输层,而是停留在了网络层,所以用 ICMP 协议进行不可达信息的传递也是合理的。

在 UDP-Ping 中除了使用上述的利用 ICMP 不可达来进行 Ping ,还有一种方式就是完全通过 UDP 协议进行发包和回包进行 Ping。这种 Ping 需要在接收方的对应端口开启一个 UDP 服务,并在应用层指定相应的收发包的规则,而发送方需要按照这样的发送规则向接收端发送请求。

这种 UDP-Ping 的方式在很多业务场景都有使用。比如检测端口服务是否是否正常,返回数据是否符合预期。这里我们着重提到需要应用层指定相应的回包策略才能完成这种 UDP-Ping ,这和 TCP 在自己的传输层层面就能完成 Ping 操作截然不同。究其原因就是 UDP 本身不依赖于建立连接,而是只通过简单的发包传达数据,这就需要上层应用来控制发包与收包的过程。

总结

前面说了这么多 Ping 的方法,不仅有大家通常理解的 ICMP-Ping,也有大家比较陌生的 UDP-Ping,TCP-Ping,可能有朋友觉得有些做法已经超出了 Ping 的工作范围,甚至需要应用层做控制才能完成 Ping 操作,这可能已经包含了整个网络传输的过程。但是不要忘了我们开头所说的 Ping 的含义:两端之间的连通性。

只是我们一般用的 Ping 仅限于 ICMP-Ping。但实际上 TCP-Ping 能解决 ICMP 包在网络层被过滤的问题,UDP-Ping 能检测对端端口的服务情况,这些操作都能在一定程度上解决更广义的两端连通性问题,而不仅仅局限于两个主机间的通信。不管是日常使用软件,还是开发具体的业务场景,我们都需要对服务可用性进行探测,不管用什么样的协议,追根到底都是类似 Ping 的操作。

虽然 Ping 对我们了解网络的连通性带来了很大的便利,但是它有以下的局限:
1.Ping 命令仅仅只能反应单次,或者是一段时间内的联通情况,但难以对数据进行相应的统计分析,产生相应的洞察;
2.Ping 命令仅仅只能反映用户端到服务端的链路联通情况,在网络架构日益复杂的情况下,实际上用户处于的网络是非常复杂的,简单的 Ping 是很难覆盖这些复杂的情况情况,没办法反映真实用户到服务器的网络情况。

而腾讯云拨测(Cloud Automated Testing,CAT)却可以利用分布于全球的监测网络,以真实终端用户使用场景为视角,提供模拟终端用户体验的拨测服务。云拨测覆盖全球主要城市和运营商,拥有 IDC、LastMile 真实网民、手机端三种类型的拨测点,拨测数据来自于真实网络环境中的真实设备,可以完整还原真实网民的使用场景。

云拨测不仅仅集成了这三种 Ping 方式,通过控制台简单配置就可以对目标地址发起 ICMP、TCP 和 UDP 三种 Ping 监测。相对于传统的 Ping 方式,云拨测具有以下的优势:
1.可以从地区、运营商维度对监测数据进行统计分析,支持地图、趋势图和散点图的方式展示监测数据;
2.支持从真实用户端获取抓包数据,以及网络的 tracert 路由数据,对真实用户端网络进行相应的分析。

图片

图片

图片

看完本文之后,如果想进一步体验甚至测试云拨测所支持的 Ping 监测和其他功能,欢迎您点击了解腾讯云云拨测:https://cloud.tencent.com/product/cat~

图片

如需了解更多监控领域的知识,欢迎关注"腾讯云监控"公众号。


http://chatgpt.dhexx.cn/article/8w5SCtTC.shtml

相关文章

同一局域网下访问vue项目

同一局域网: 在你的电脑上用快捷键windows R打开cmd,使用ping ip地址(想要访问你项目的那台电脑的ip地址),如果成功后就表示你们处于同一局域网下。 本机ip地址 在你的电脑上用快捷键windows R打开cmd&#xff…

【Java 并发编程】一文详解 Java 中有几种创建线程的方式

Java 中有几种创建线程的方式? 1. Java 程序天然就是多线程的2. 线程的启动与终止2.1 线程的启动(1)继承 Thread 类,重写 run() 方法(2)实现 Runnable 接口,重写 run() 方法(3)Thre…

【操作系统】创建线程的方式

学习目标: 目标:掌握操作系统知识 学习内容: 本文内容:创建线程的方式 文章目录 学习目标:学习内容:1创建线程的方法一 : 继承Thread类1.1 写法一1.2 写法二 2 创建线程的方法二 :…

想不到吧,Java创建线程的方式只有一种

目录 前言继承Thread方式实现Runnable接口实现callable接口总结 前言 看到这个标题的小伙伴先别着急喷我……在面试的时候,我们经常会被问到这种基础题:Java创建线程的方式有几种? 比较正常的答法当然是三种: 继承Thread实现Ru…

【 java 多线程】创建多线程的方式三:使用 Callable 接口创建多线程

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言&#x1f4d…

关于创建线程的方式有几种

导语 在我们平常的面试中,我们经常会被面试官问道:你知道Java中多线程的实现方式有几种吗?在网上刷过面试题的童鞋们,一般都会说两种:继承Thread、实现Runnable,甚至还有甚者可能会说三种、四种的&#xf…

Java创建线程的方式只有一种:Thread+Runnable

Java创建线程的方式其实只有一种 👨‍🎓一、继承Thread👨‍🎓二、实现Runnable接口👨‍🎓三、实现Callable接口👨‍🎓四、通过线程池创建👨‍🎓五、总结 一般…

java中创建线程的4种方式

写在前面的话 java线程创建方式有几种?这种问题在面试中经常被问到,你可能心里马上反映出两种方式(实现Runnable、继承Thread),当你把这两种叙述给面试官听后,面试官会觉得你该掌握的知识已经有了&#xf…

【 java 多线程】创建多线程的方式四:使用线程池创建多线程

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言&#x1f4d…

创建线程的方式

一般来说,创建线程有三种方式:继承 Thread 类、实现 Runnable 接口和实现 Callable 接口。 继承 Thread 类:继承 Thread 类,重写 run() 方法,调用 start() 方法启动线程。 public class MyThread {public static cla…

【JAVAEE】创建线程的方式及线程的常用方法

目录 1.创建线程的四种方式 1.1继承Thread类 1.2实现Runnable接口 1.3匿名内部类 1.4lambda表达式 2.多线程的优势-增加运行速度 3.Thread类及常用方法 3.1构造方法 3.2常见属性 演示后台线程 演示线程是否存活 3.3线程中断 3.4线程等待-join() 3.5获取当前线程 …

创建线程的方式有那些?

目录 一.创建线程的4种方式 二.创建线程方式有什么区别? 一.创建线程的4种方式 (1)写一个类继承Thread,覆盖重写run方法 (2)创建一个Runnable类型的对象,实现run()方法,传入Thread的构造方法中 &#x…

创建线程几种方式

创建线程的几种方式: 方式1:通过继承Thread类创建线程 步骤:1.定义Thread类的子类,并重写该类的run方法,该方法的方法体就是线程需要执行的任务,因此run()方法也被称为线程执行体 2.创建Thread子类的实例&a…

线程创建的四种方式

java中创建线程的四种方法以及区别 Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线程 3&am…

四种线程创建方式

一. 继承Thread类 继承Thread类创建线程的步骤: 创建一个自定义类继承Thread类,重写run()方法,将所要单独线程运行写入run()方法中;创建Thread类的子类的对象;调用该对象的start()方法,该start()方法表示开启线程,然后调用执行run方法; Testpublic void test() {Thread.curre…

创建线程的四种方式

我们创建线程池一般有四种方式,分别是: 1.继承Thread类,重写run()方法; 2.实现Runnable接口,重写run()方法; 3.实现Callable接口,重写call()方法; 4.使用线程池创建线程;…

线程创建常用的四种方式

java中创建线程的四种方法以及区别 Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线程 3&…

银行测试核心项目之测试阶段分享

最近有小伙伴说「想了解核心系统建设中,冒烟、SIT、UAT、回归测试的重点,如何设计测试案例,或相关的资料推荐等」。 这个话题很笼统,测试这一块儿除了业务测试,还有性能测试、安全测试等;以及不同的角色对…

金融银行测试面试题分享

1、网上银行转账是怎么测的,设计一下测试用例。 回答思路: 宏观上可以从质量模型(万能公式)来考虑,重点需要测试转账的功能、性能与安全性。设计测试用例可以使用场景法为主,先列出转账的基本流和备选流。…

2022年软件测试——精选金融银行面试真题

前言 小伙伴们好久不见呀,现已经到了八月份了过了这一个月就是金九银十了,在这里呢笔者给大家准备了一份软件测试金融方面的面试题,笔者在这里就不多说废话了哟,咱们直接进入正题哈。 1、P2P你们也测试后台管理吗?个人…