【Shell 命令集合 网络通讯 】⭐⭐⭐Linux 测试与目标主机之间的网络连接ping 命令 使用指南

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云防火墙,500元 1000GB
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【Shell 命令集合 网络通讯 】⭐⭐⭐Linux 测试与目标主机之间的网络连接ping 命令 使用指南

Shell 命令专栏:Linux Shell 命令全解析


描述


在Linux中,ping命令用于测试与目标主机之间的网络连接。它发送一个ICMP回显请求(ping请求)到目标主机,并等待接收一个ICMP回显回复(ping回复)。通过发送ping请求和接收ping回复,ping命令可以确定目标主机是否可达、网络连接是否正常以及网络延迟。

当我们使用ping命令时,它会向目标主机发送一个ICMP Echo Request消息,并等待主机的ICMP Echo Reply消息。通过计算发送请求和接收回复之间的时间差,ping命令可以测量往返时间(Round-Trip Time,RTT),从而估计网络延迟。

除了测量网络延迟,ping命令还可以检测目标主机的可达性。如果目标主机无法接收到ping请求或无法发送ping回复,那么ping命令将显示一条错误消息,表明目标主机不可达或存在网络连接问题。

通过连续发送ping请求,ping命令还可以提供关于网络连接的统计信息。它可以显示每个ping请求的往返时间、丢包率(即无法接收到回复的请求的百分比)以及最小、最大和平均往返时间。

总结来说,ping命令在Linux中的作用是:

  • 测试与目标主机之间的网络连接是否正常。
  • 测量网络延迟(往返时间)。
  • 检测目标主机的可达性。
  • 提供关于网络连接的统计信息。

语法格式

ping [options] destination

参数说明

  • -c count:指定发送ping请求的次数。
  • -s packetsize:指定每个ping请求的数据包大小。
  • -i interval:指定发送ping请求之间的时间间隔。
  • -t timeout:指定等待ping回复的超时时间。
  • -q:以静默模式运行,只显示总结信息。
  • -A:显示每个ping请求的详细信息,包括IP地址、TTL、往返时间等。
  • -R:启用记录路由选项,显示每个ping请求经过的路由节点的IP地址。

错误情况

  • 如果目标主机不可达或网络连接有问题,ping命令将显示"Destination Host Unreachable"(目标主机不可达)或"Network is unreachable"(网络不可达)的错误消息。
  • 如果ping请求超时,即无法在指定的超时时间内接收到ping回复,ping命令将显示"Request timeout"(请求超时)的错误消息。
  • 如果ping请求被目标主机或网络设备阻止,ping命令将显示"Destination Port Unreachable"(目标端口不可达)或"Request timed out"(请求超时)的错误消息。

请注意,错误消息可能因操作系统或网络设备的不同而有所差异。

注意事项

在使用Linux shell中的ping命令时,有一些注意事项需要注意:

  1. 需要特定的权限:默认情况下,ping命令需要root或具有特定权限的用户才能执行。如果当前用户没有足够的权限,可以使用sudo命令来获取root权限。
  2. 防火墙和网络策略:在某些情况下,防火墙或网络策略可能会阻止ping命令的执行或回复。确保目标主机允许接收ping请求,并且网络中的防火墙或策略不会阻止ping请求的传输。
  3. 目标主机可达性:在执行ping命令之前,请确保目标主机处于可达状态,即目标主机正常运行且与本地主机在同一网络中。如果目标主机不可达,ping命令将无法发送请求或接收回复。
  4. 超时时间设置:通过使用ping命令的-t参数可以设置等待ping回复的超时时间。根据网络环境的不同,可以适当调整超时时间,以确保在合理的时间范围内得到回复。
  5. 数据包大小:使用ping命令的-s参数可以设置每个ping请求的数据包大小。请注意,过大的数据包可能会导致网络拥塞或被防火墙阻止。确保数据包大小适合当前网络环境。
  6. 网络延迟和丢包率:ping命令提供了有关网络延迟和丢包率的统计信息。通过观察平均往返时间和丢包率,可以评估网络连接的质量和稳定性。
  7. 注意使用连续模式:使用ping命令的-t参数可以启用连续模式,即持续发送ping请求。在使用连续模式时,请确保在需要时手动中断命令,以避免无限期地发送ping请求。
  8. 不要滥用ping命令:由于ping命令会产生网络流量,滥用ping命令可能会对网络性能产生负面影响。请谨慎使用ping命令,避免过度使用或在不必要的情况下频繁执行。

总之,在使用Linux shell中的ping命令时,需要注意权限、网络可达性、防火墙和策略、超时时间、数据包大小等因素,以确保正确使用ping命令并获取准确的网络连接信息。


底层实现

Linux shell中的ping命令底层是通过使用套接字(socket)和Internet控制消息协议(ICMP)来实现的。

具体实现步骤如下:

  1. 创建一个原始套接字:ping命令首先创建一个原始套接字,这样它就可以直接访问网络层,而不是通过传输层协议(如TCP或UDP)。
  2. 构建ICMP Echo Request消息:ping命令构建一个ICMP Echo Request消息,该消息包含一个唯一的标识符和序列号,以便将请求与回复进行匹配。
  3. 计算校验和:在发送ICMP Echo Request消息之前,ping命令需要计算校验和。校验和是一个简单的算法,用于检测数据在传输过程中是否被修改。
  4. 发送ICMP Echo Request消息:ping命令使用原始套接字发送构建的ICMP Echo Request消息到目标主机。它将目标主机的IP地址作为目标地址,并设置IP头部的TTL(生存时间)字段。
  5. 接收ICMP Echo Reply消息:一旦目标主机接收到ICMP Echo Request消息,它将发送一个ICMP Echo Reply消息作为回复。ping命令使用原始套接字接收这个回复,并提取其中的信息。
  6. 解析ICMP Echo Reply消息:ping命令解析接收到的ICMP Echo Reply消息,提取其中的往返时间和其他相关信息。
  7. 显示结果:ping命令将解析的结果显示在终端上,包括往返时间、丢包率以及其他统计信息。

需要注意的是,ping命令在底层使用了原始套接字,这需要一定的权限,并且在某些系统中可能需要特定的配置。此外,底层实现可能会因操作系统和网络设备的不同而有所差异。


示例

示例一

ping -c 5 www.google.com

该命令将向www.google.com发送5个ping请求,并等待接收5个ping回复。然后,它将显示每个ping请求的往返时间、丢包率以及最小、最大和平均往返时间。

示例二

ping -s 1000 192.168.0.1

该命令将向IP地址为192.168.0.1的主机发送ping请求,其中-p参数指定了每个ping请求的数据包大小为1000字节。

示例三

ping -i 2 10.0.0.1

该命令将向IP地址为10.0.0.1的主机发送ping请求,并设置每个ping请求之间的时间间隔为2秒。

示例四

ping -t 10 www.example.com

该命令将连续向www.example.com发送ping请求,直到手动中断(Ctrl+C)。它将显示每个ping请求的往返时间、丢包率以及最小、最大和平均往返时间。

示例五

ping -q -c 3 192.168.1.1

该命令将向IP地址为192.168.1.1的主机发送3个ping请求,并以静默模式运行,只显示总结信息而不显示每个ping请求的详细信息。

示例六

ping -A 8.8.8.8

该命令将向IP地址为8.8.8.8的主机发送ping请求,并显示每个ping请求的详细信息,包括IP地址、TTL(生存时间)、往返时间等。

示例七

ping -R 172.16.0.1

该命令将向IP地址为172.16.0.1的主机发送ping请求,并启用记录路由选项。它将显示每个ping请求经过的路由节点的IP地址。


用c语言实现


以下是一个使用C语言实现ping命令的示例代码,包含了详细的注释说明:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#define PACKET_SIZE 64
#define MAX_WAIT_TIME 5
// ICMP报文结构
struct icmp_packet {
    struct icmphdr header;
    char data[PACKET_SIZE - sizeof(struct icmphdr)];
};
// 计算校验和
unsigned short calc_checksum(unsigned short *addr, int len) {
    unsigned int sum = 0;
    unsigned short answer = 0;
    unsigned short *w = addr;
    int nleft = len;
    // 将16位的数据累加起来
    while (nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }
    // 如果数据长度为奇数,将最后一个字节的值也加到sum中
    if (nleft == 1) {
        *(unsigned char *)(&answer) = *(unsigned char *)w;
        sum += answer;
    }
    // 将高16位与低16位相加
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return answer;
}
// 发送ICMP Echo Request报文
void send_ping(int sockfd, struct sockaddr_in *dest_addr, int seq) {
    struct icmp_packet packet;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    // 设置ICMP报文头部
    packet.header.type = ICMP_ECHO;
    packet.header.code = 0;
    packet.header.un.echo.id = getpid();
    packet.header.un.echo.sequence = seq;
    packet.header.checksum = 0;
    packet.header.checksum = calc_checksum((unsigned short *)&packet, sizeof(packet));
    // 发送ICMP Echo Request报文
    if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)dest_addr, sizeof(struct sockaddr)) == -1) {
        perror("sendto");
        exit(1);
    }
}
// 接收ICMP Echo Reply报文
int receive_ping(int sockfd, struct sockaddr_in *src_addr, int seq, struct timeval *tv_sent) {
    struct icmp_packet packet;
    struct sockaddr_in from;
    socklen_t fromlen = sizeof(from);
    struct timeval tv_recv;
    int ret;
    // 接收ICMP Echo Reply报文
    if ((ret = recvfrom(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&from, &fromlen)) == -1) {
        perror("recvfrom");
        exit(1);
    }
    // 获取接收时间
    gettimeofday(&tv_recv, NULL);
    // 检查接收到的报文是否是ICMP Echo Reply报文
    if (packet.header.type == ICMP_ECHOREPLY && packet.header.un.echo.id == getpid() && packet.header.un.echo.sequence == seq) {
        // 计算往返时间
        double rtt = (tv_recv.tv_sec - tv_sent->tv_sec) * 1000 + (tv_recv.tv_usec - tv_sent->tv_usec) / 1000.0;
        // 打印结果
        printf("Reply from %s: icmp_seq=%d ttl=%d time=%.2fms\n", inet_ntoa(from.sin_addr), seq, packet.header.un.echo.id, rtt);
        return 1;
    }
    return 0;
}
int main(int argc, char *argv[]) {
    int sockfd;
    struct sockaddr_in dest_addr;
    struct hostent *host;
    int seq = 1;
    if (argc != 2) {
        printf("Usage: %s <hostname/IP>\n", argv[0]);
        exit(1);
    }
    // 创建原始套接字
    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
        perror("socket");
        exit(1);
    }
    // 获取目标主机IP地址
    if ((host = gethostbyname(argv[1])) == NULL) {
        perror("gethostbyname");
        exit(1);
    }
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr = *((struct in_addr *)host->h_addr);
    // 发送ICMP Echo Request报文并接收ICMP Echo Reply报文
    while (1) {
        struct timeval tv_sent;
        send_ping(sockfd, &dest_addr, seq);
        gettimeofday(&tv_sent, NULL);
        if (receive_ping(sockfd, &dest_addr, seq, &tv_sent)) {
            // 接收到ICMP Echo Reply报文,继续发送下一个ICMP Echo Request报文
            seq++;
        }
        // 等待一段时间,继续发送下一个ICMP Echo Request报文
        sleep(1);
    }
    close(sockfd);
    return 0;
}

这个示例代码使用了原始套接字来发送和接收ICMP Echo Request和Echo Reply报文,实现了基本的ping功能。它使用了ICMP报文结构、计算校验和、发送和接收函数等来实现ping命令的功能。请注意,使用原始套接字需要root权限或特定的权限,因此需要以root用户或具有特定权限的用户运行该程序。


结语

在我们的探索过程中,我们已经深入了解了Shell命令的强大功能和广泛应用。然而,学习这些技术只是开始。真正的力量来自于你如何将它们融入到你的日常工作中,以提高效率和生产力。

心理学告诉我们,学习是一个持续且积极参与的过程。所以,我鼓励你不仅要阅读和理解这些命令,还要动手实践它们。尝试创建自己的命令,逐步掌握Shell编程,使其成为你日常工作的一部分。

同时,请记住分享是学习过程中非常重要的一环。如果你发现本博客对你有帮助,请不吝点赞并留下评论。分享你自己在使用Shell命令时遇到的问题或者有趣的经验,可以帮助更多人从中学习。

此外,我也欢迎你收藏本博客,并随时回来查阅。因为复习和反复实践也是巩固知识、提高技能的关键。

最后,请记住:每个人都可以通过持续学习和实践成为Shell编程专家。我期待看到你在这个旅途中取得更大进步!

目录
相关文章
|
29天前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
73 8
|
29天前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
204 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
76 3
|
1天前
|
NoSQL 关系型数据库 MySQL
《docker高级篇(大厂进阶):4.Docker网络》包括:是什么、常用基本命令、能干嘛、网络模式、docker平台架构图解
《docker高级篇(大厂进阶):4.Docker网络》包括:是什么、常用基本命令、能干嘛、网络模式、docker平台架构图解
74 56
《docker高级篇(大厂进阶):4.Docker网络》包括:是什么、常用基本命令、能干嘛、网络模式、docker平台架构图解
|
11天前
|
Linux Shell
Linux 10 个“who”命令示例
Linux 10 个“who”命令示例
39 14
Linux 10 个“who”命令示例
|
27天前
|
Linux iOS开发 网络架构
如何使用 Ping 命令监测网络丢包情况?
如何使用 Ping 命令监测网络丢包情况?
103 48
|
20天前
|
Linux 数据库
Linux中第一次使用locate命令报错?????
在Linux CentOS7系统中,使用`locate`命令时出现“command not found”错误,原因是缺少`mlocate`包。解决方法是通过`yum install mlocate -y`或`apt-get install mlocate`安装该包,并执行`updatedb`更新数据库以解决后续的“can not stat”错误。
30 9
|
18天前
|
监控 网络协议 Linux
Linux netstat 命令详解
Linux netstat 命令详解
|
24天前
|
运维 监控 网络协议
运维工程师日常工作中最常用的20个Linux命令,涵盖文件操作、目录管理、权限设置、系统监控等方面
本文介绍了运维工程师日常工作中最常用的20个Linux命令,涵盖文件操作、目录管理、权限设置、系统监控等方面,旨在帮助读者提高工作效率。从基本的文件查看与编辑,到高级的网络配置与安全管理,这些命令是运维工作中的必备工具。
84 3
|
29天前
|
存储 运维 Linux
如何在 Linux 系统中使用 envsubst 命令替换环境变量?
`envsubst` 是 Linux 系统中用于替换文本中环境变量值的实用工具。本文分三部分介绍其工作原理、使用方法及实际应用,包括配置文件替换、脚本执行中环境变量替换和动态生成文件等场景,帮助用户高效利用 `envsubst` 进行开发和运维工作。
48 4