前言

ping命令是一种比较好用的网络诊断工具,常用来验证链路问题,例如 ping traceroute mtr 都使用的 “ICMP” 包来测试 Internet 两点之间的网络连接状况。生产环境中, 网络是否稳定(网络时延)是一个很重要的指标. 为了方便检查网络时延的大小, 我们可以通过ping命令实现长时间的网络监控。

本文主要记录了Linux环境如何使用ping命令+时间戳实时输出保存到文件里面的解决方案

更新历史

2021年06月06日 - 初稿

阅读原文 - https://wsgzao.github.io/post/ping/


ping简介

ping大家可能每天都在使用,不多做介绍了

ping(呯)是一种计算机网络工具,用来测试数据包能否透过IP协议到达特定主机。ping的运作原理是向目标主机传出一个ICMP的请求回显数据包,并等待接收回显回应数据包。程序会按时间和成功响应的次数估算丢失数据包率(丢包率)和数据包往返时间(网络时延,Round-trip delay time)。

直接ping ip即可。

若显示ping的回显时间,此命令也提供了参数 -D来回显时间戳。

1
2
3
4
5
6
7
8
9
10
11
12
13
# ping baidu.com -D
PING baidu.com (39.156.69.79) 56(84) bytes of data.
[1623205720.047547] 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=23 time=274 ms
[1623205720.321747] 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=23 time=274 ms
[1623205721.322361] 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=23 time=274 ms
[1623205722.323220] 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=4 ttl=23 time=274 ms
[1623205723.324359] 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=5 ttl=23 time=274 ms

# 文章后面介绍了两种方法,我倾向于使用fflush()
ping baidu.com -i 1 | awk '{ print strftime("%Y-%m-%d-%H:%M:%S",systime())" | " $0; fflush() }' >> ping-baidu.com.txt &
2021-06-11-07:24:58 | 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=37 time=182 ms
2021-06-11-07:24:59 | 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=2 ttl=37 time=181 ms
2021-06-11-07:25:01 | 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=4 ttl=37 time=181 ms

然而,时间戳可读性较差,虽然可以利用网上的一些工具(unitxtime)来转化,但是比较麻烦,最好的方式时回显时就是可读性较好的时间格式。

ping命令的使用

常用参数

-i: 每次执行ping操作的间隔时间, 默认是1s;

-c: 执行ping操作的次数, 默认是一直执行, 除非被中断;

-s: 指定执行ping操作时发送的包的大小, 默认是56B, 添加报文头之后, 最终发送的是64B.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 在终端 ping 某个地址, 执行10次
ping baidu.com -c 10 | awk '{ print $0"\t" strftime("%H:%M:%S",systime()) } '
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=40 time=83.3 ms 10:41:23
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.4 ms 10:41:24
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.4 ms 10:41:25

# 日期在后面
ping baidu.com | awk '{ print $0"\t" strftime("%Y-%m-%d %H:%M:%S",systime()); fflush()}'
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=40 time=83.2 ms 2021-06-09 10:42:45
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.3 ms 2021-06-09 10:42:46
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.3 ms 2021-06-09 10:42:47

# 日前在前面
ping baidu.com | awk '{ print strftime("%Y.%m.%d %H:%M:%S",systime())"\t" $0; fflush() }'
2021.06.09 10:43:28 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=46 time=162 ms
2021.06.09 10:43:29 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=2 ttl=46 time=177 ms
2021.06.09 10:43:30 64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=3 ttl=46 time=174 ms

ping将输出重定向到指定文件

使用fflush

注意:使用fflush(),不然文件不会有信息,因为awk也是有缓存的。

为防止脚本被中断, 可以通过 nohup 令脚本在后台执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 下面未加fflush(),执行命令生成文件会等一会才会有信息打印到文件里
nohup ping baidu.com | awk '{ print strftime("%Y-%m-%d %H:%M:%S",systime())"\t" $0; fflush() }' >> long_ping.txt &
$ tail -f long_ping.txt
2021-06-09 10:45:54 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.3 ms
2021-06-09 10:45:55 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.3 ms
2021-06-09 10:45:56 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=4 ttl=40 time=83.3 ms

# 要结束后台进程, 可通过下述方式查找并kill
$ ps -ef |grep ping
user00 5778 30382 0 10:45 pts/2 00:00:00 ping baidu.com
user00 7133 30382 0 10:48 pts/2 00:00:00 grep --color=auto ping
$ kill -9 5778
[1]+ Done nohup ping baidu.com | awk '{ print strftime("%Y.%m.%d %H:%M:%S",systime())"\t" $0; fflush() }' >> long_ping.txt

使用pong

  1. 什么是pingpong?

pingpong是一种数据缓存的手段,通过pingpong操作可以提高数据传输的效率。

  1. 什么时候需要pingpong?

在两个模块间交换数据时,上一级处理的结果不能马上被下一级所处理完成,这样上一级必须等待下一级处理完成才可以送新的数据,这样就会对性能产生很大的损失。

引入pingpong后我们可以不去等待下一级处理结束,而是将结果保存在pong路的缓存中,pong路的数据准备好的时刻,ping路的数据也处理完毕(下一级),然后无需等待直接处理pong路数据,上一级也无需等待,转而将结果存储在ping路。这样便提高了处理效率。

1
nohup ping baidu.com -i 1 | while read pong; do echo "$(date +"%Y-%m-%d %H:%M:%S") | $pong"; done | tee -a ping-baidu.com.log &

date时间戳

数据戳转化

date可以将时间戳转化为localtime。

1
2
3
4
5
6
# date -d @1623205723.324359
Wed Jun 9 10:28:43 CST 2021
# date --date=@1623205723.324359
Wed Jun 9 10:28:43 CST 2021
利用awk进行转化,比较麻烦。

awk拼接

1
2
3
4
5
6
7
8
9
10
11
# 格式可以自定义调整
ping baidu.com | awk '{"date" | getline date; print date,$0}'
Wed Jun 9 10:33:01 CST 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.3 ms
Wed Jun 9 10:33:01 CST 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.5 ms
Wed Jun 9 10:33:01 CST 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=4 ttl=40 time=83.3 ms

# 时间格式可根据date自定义
ping baidu.com | awk -v date="$(date +"%Y-%m-%d %r")" '{print date, $0}'
2021-06-09 10:33:38 AM 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=40 time=83.3 ms
2021-06-09 10:33:38 AM 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.5 ms
2021-06-09 10:33:38 AM 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.6 ms

perl

如果 awk 没有 strftime()

Notice:报错“Can’t locate Time/Piece.pm in @INC”,需要执行命令yum -y install perl-Time-Piece来进行必要包的安装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 要将其重定向到文件,请使用标准shell重定向并关闭输出缓冲:
ping baidu.com | perl -nle 'print scalar(localtime), " ", $_'
Wed Jun 9 10:36:14 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.4 ms
Wed Jun 9 10:36:15 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.5 ms
Wed Jun 9 10:36:16 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=4 ttl=40 time=83.3 ms

# 如果显示ISO8601时间格式
ping baidu.com | perl -nle 'BEGIN {$|++} print scalar(localtime), " ", $_'
Wed Jun 9 10:36:41 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=40 time=83.3 ms
Wed Jun 9 10:36:42 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.3 ms
Wed Jun 9 10:36:43 2021 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.5 ms

ping baidu.com | perl -nle 'use Time::Piece; BEGIN {$|++} print localtime->datetime, " ", $_'
2021-06-09T10:37:08 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=40 time=83.4 ms
2021-06-09T10:37:09 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=40 time=83.4 ms
2021-06-09T10:37:10 64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=3 ttl=40 time=83.2 ms

知识补充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
strftime补充:
函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明串strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大小写的。
%a 星期几的简写
%A 星期几的全称
%b 月份的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的前两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年份,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从1到7,星期一为1)
%U 第年的第几周,把星期日作为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号
语法
strftime(format,timestamp)参数 描述
format 可选。规定如何返回结果。
timestamp 可选。时间戳,默认是当前本地的


awk补充:

awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。


print与printf补充:

print 中不能使用%s ,%d 或%c;print 自动换行,printf 没有自动换行

文章目录
  1. 1. 前言
  2. 2. 更新历史
  3. 3. ping简介
  4. 4. ping命令的使用
  5. 5. ping将输出重定向到指定文件
    1. 5.1. 使用fflush
    2. 5.2. 使用pong
  6. 6. date时间戳
    1. 6.1. 数据戳转化
    2. 6.2. awk拼接
    3. 6.3. perl
  7. 7. 知识补充