通过 Popen 帮助 ping
我正在开发一种软件来监控与不同位置的通信。 原理很简单:每秒发送一次 ping 并实时显示结果(毫秒延迟、数据包丢失等)。
还需要注意的是,我是在 Linux 上运行该软件,因此为了从我的软件中执行 ping 操作,我选择了subporocess.Popen 方式,因为打开套接字需要您以 root 用户身份登录。我不想给每个人对服务器的 root 访问权限。
这是负责 ping 的类:
class WorkerThread(QThread):
def __init__(self,receiver,sitename):
QThread.__init__(self)
global time_manager
time_manager[sitename] = [time.time(),0,0] #for statistic purpeses
self.stopped = 0
self.receiver = receiver
self.sitename = sitename
def run(self):
icmp_count = 0
ping_result = ""
packeloss_result = ""
while not self.stopped:
data = subprocess.Popen("ping -c1 "+str(sites[self.sitename]),shell = True,stdout=subprocess.PIPE)
data.wait()
time_manager[self.sitename][1] +=1 #counts the icmps sent
bufferdata = data.stdout.read()
ping_result = ms_pat.findall(bufferdata)
packeloss_result = packetloss_pat.findall(bufferdata)
if ping_result:
ping_ms = ping_result[0][0]
if packeloss_result:
time_manager[self.sitename][2] +=1
ping_ms = "-1"
ms_count[self.sitename].append(float(ping_ms))
time.sleep(1)
event = QCustomEvent(12345)
event.setData(self.sitename+ping_ms)
QApplication.postEvent(self.receiver, event)
def stop(self):
self.stopped = 1
我使用线程,因为有时我需要对不同的站点运行多个 ping 作业。
我的问题是这样的: 运行时,我得到了完美的毫秒延迟结果,但每隔几次 ping,我都会得到不准确的结果,高于实际应有的结果。
我知道结果不准确,因为我同时从控制台运行 ping,但没有得到 ping 峰值
示例:
ping_ms = 20.0
ping_ms = 21.31
ping_ms = 23.23
ping_ms = 80.2
ping_ms = 23.23
ping_ms = 24.2
我不明白为什么会发生这种情况。也许我需要以不同的方式编写代码。如果有人可以帮助我,我将不胜感激。
谢谢。
我已经隔离了问题:
看来问题不在代码中,而是在操作系统或 ping 命令本身中。 当我每秒在控制台中手动运行命令:“ping -c1 xxx.xxx.xxx.xxx”时,经过几次尝试后,我得到了相同的结果,一个奇怪的 ping 峰值。但如果 ping 流畅“ping xxx.xxx.xxx.xxx”,则不会出现尖峰。
是否可以从脚本中使用 Popen 运行流畅的 ping 并读取结果?
I'm developing a software to monitor communication to different locations.
the principle is simple: send ping every second and display the results in real time (ms delay, packet loss etc)
It's also important to mention that I'm running the software from Linux, so in order to ping from my software i choose the subporocess.Popen way, because opening sockets require you to be logged as root user. And i don't want to give everyone root access to the server..
Here is the class reponsible for the pinging:
class WorkerThread(QThread):
def __init__(self,receiver,sitename):
QThread.__init__(self)
global time_manager
time_manager[sitename] = [time.time(),0,0] #for statistic purpeses
self.stopped = 0
self.receiver = receiver
self.sitename = sitename
def run(self):
icmp_count = 0
ping_result = ""
packeloss_result = ""
while not self.stopped:
data = subprocess.Popen("ping -c1 "+str(sites[self.sitename]),shell = True,stdout=subprocess.PIPE)
data.wait()
time_manager[self.sitename][1] +=1 #counts the icmps sent
bufferdata = data.stdout.read()
ping_result = ms_pat.findall(bufferdata)
packeloss_result = packetloss_pat.findall(bufferdata)
if ping_result:
ping_ms = ping_result[0][0]
if packeloss_result:
time_manager[self.sitename][2] +=1
ping_ms = "-1"
ms_count[self.sitename].append(float(ping_ms))
time.sleep(1)
event = QCustomEvent(12345)
event.setData(self.sitename+ping_ms)
QApplication.postEvent(self.receiver, event)
def stop(self):
self.stopped = 1
I'm using threads because sometimes i need to run multiple ping jobs to different sites.
My problem is this:
when running, i get the ms delay results perfectly, but every few pings i get a not accurate result, higher then what it actually should be.
I know that the results are not accurate, because i run ping from a console at the same time, and there i don't get that ping spike
Example:
ping_ms = 20.0
ping_ms = 21.31
ping_ms = 23.23
ping_ms = 80.2
ping_ms = 23.23
ping_ms = 24.2
I don't understand why this is happening. maybe i need to write the code differently. if someone could help me, it will be much appreciated.
thanks.
i have isolated the problem:
It seems that the problem is not in the code, but in the OS or in the ping command itself.
when i run manually every second in console the command: "ping -c1 xxx.xxx.xxx.xxx" after few attempts i get the same result ,a weird ping spike. but if the ping fluent "ping xxx.xxx.xxx.xxx", there are no spikes.
Is it possible to run fluent ping with Popen from a script and read the results?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这看起来是一个很好的起点:
http://pypi.python.org/pypi/ping/0.1
当然,目前还不清楚你现在所做的事情是否真的有任何问题。由于 ping 时间是从 ping 的输出中解析出来的,所以我们不能归咎于进程生成开销或其他什么。
This looks like a good starting point:
http://pypi.python.org/pypi/ping/0.1
Of course, it's not clear that there is any problem with what you're doing now really. Since the ping time is being parsed from the output of ping it's not like we can blame process spawning overhead or something.
尝试将
close_fds=True
添加到您的Popen
调用中(请参阅讨论 此处)。如果您在其他线程中打开了其他管道,则它们可能以某种方式进行交互(强制线程的特定顺序)。考虑使用 Popen.communicate() 而不是直接从进程的 stdout 流中读取。话虽如此,您的 ping 实现似乎不太可能根据其输出的缓冲程度返回不同的读数。在更高的层面上,您应该记住 ping 计时数据本质上是不可靠的。如果您无法修复峰值,并且您确信它是
Popen
调用的产物(而不仅仅是随机噪声),那么对数据进行后处理可能是合理的。例如,您可以一次收集 5 个数据点并取中值。 (请注意,中位数对异常值的敏感度低于平均值)。这并不比ping
已经在做的事情更糟糕。更新 26/02
很抱歉听到 ^ 没有帮助。其他一些想法:
1.如果我们更多地了解如何从 shell 运行
ping
,可能会有帮助。在 python 中,您使用-c1
将ping
限制为一次尝试。我猜测,在 shell 中,您只是运行ping hostname
并实时查看结果 - 这是真的吗?如果是这样,请尝试运行 bash 脚本,如下所示:并仔细查看结果。峰值可能是您调用
ping
的方式造成的。2. 您的示例代码没有正则表达式定义。您是否 100% 确定他们从 ping 输出中捕获了准确正确的值?
Try adding
close_fds=True
to yourPopen
call (see discussion here). If you have other pipes open in other threads, it may be the case that they are interacting somehow (forcing a particular ordering of threads). Consider usingPopen.communicate()
rather than reading from the process' stdout stream directly. With that said, it seems unlikely that your ping implementation would return different readings based on how well its output is being buffered.At a higher level, you should keep in mind that ping timing data is inherently unreliable. If you can't fix the spike, and you're convinced it is an artefact from the
Popen
call (rather than just random noise), then it is probably reasonable to post-process the data. For example, you could collect 5 datapoints at a time and take the median. (Note that the median is less sensitive to outliers than the average). This is no worse than whatping
is already doing.Update 26/02
Sorry to hear ^ didn't help. Couple of other ideas:
1. It might be helpful if we know a bit more about how you're running
ping
from the shell. In python, you're using-c1
to limitping
to a single try. I am guessing that, in the shell, you are simply runningping hostname
and watching the results in real time -- is this true? If so, please try running a bash script as follows:And look very carefully at the results. It is possible that the spikes are the result of how you're calling
ping
.2. Your sample code doesn't have your regex definitions. Are you 100% sure they are capturing the exact right values from ping's output?