前言
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 (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
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 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
- 什么是pingpong?
pingpong是一种数据缓存的手段,通过pingpong操作可以提高数据传输的效率。
- 什么时候需要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 没有自动换行
|