如何在python中执行ping或traceroute,在生成时访问输出?

时间:2009-07-20 05:53:54

标签: python ping traceroute

早些时候,我问过这个问题:

How can I perform a ping or traceroute using native python?

但是因为python没有以root身份运行,所以它无法打开在本机python中执行ping / traceroute所需的原始ICMP套接字。

这让我回到使用系统的ping / traceroute shell命令。这个问题有几个使用subprocess模块的例子似乎运作良好:

Ping a site in Python?

我还有一个要求:我需要能够在生成时访问输出(例如,对于长时间运行的traceroute。)

上面的示例都运行shell命令,然后只有在命令完成后才能访问完整输出。有没有办法在生成命令输出时访问它?

编辑:根据Alex Martelli的回答,这是有效的:

import pexpect

child = pexpect.spawn('ping -c 5 www.google.com')

while 1:
        line = child.readline()
        if not line: break
        print line,

4 个答案:

答案 0 :(得分:6)

pexpect是我达到的目标,“默认情况下”,对于任何需求,例如你的 - 还有其他类似的模块,但是pexpect几乎总是最丰富,最稳定,最成熟的模块。如果我不得不在Windows下正确运行(ping和traceroute可能有他们自己的问题),那么我会费心寻找替代方案的一个案例 - 让我们知道你是否就是这种情况,我们会看看可以安排什么! - )

答案 1 :(得分:4)

您应该阅读subprocess模块的文档,它描述了如何运行外部进程并实时访问其输出。

基本上,你做

from subprocess import Popen, PIPE
p = Popen(['tracert', host], stdout=PIPE)
while True:
    line = p.stdout.readline()
    if not line:
        break
    # Do stuff with line

实际上,您链接的SO问题中的答案非常接近您的需求。 Corey Goldberg's answer使用了一个管道readline,但由于它与-n 1运行ping,因此它的持续时间不足以产生影响。

答案 2 :(得分:1)

您可以为子流程创建一个tty对,并在其中运行。根据C标准(C99 7.19.3),唯一的时间stdout是行缓冲的(与完全缓冲相反,这是你所说的你不想要的)是它的终端。 (或者孩子显然叫做setvbuf())。

查看os.openpty()。

未经测试的代码:

master, slave = os.openpty()
pid = os.fork()
if pid == 0:
    os.close(master)
    os.dup2(slave, 0)
    os.dup2(slave, 1)
    os.dup2(slave, 2)
    os.execv("/usr/sbin/traceroute", ("traceroute","4.2.2.1"))
    # FIXME: log error somewhere
    os.exit(1)
os.close(slave)
while True:
    d = os.read(master)
    if len(d) == 0:
        break
    print d
os.waitpid(pid, 0)

请注意,让子进程(在fork()之后)调用setvbuf()将工作,因为setvbuf()是一个libc函数而不是一个系统调用。它只是改变当前进程输出的状态,当加载新的二进制文件时,它将在exec调用时被覆盖。

答案 3 :(得分:1)

这是另一种方法:

# const_output.py
import sys
from subprocess import Popen

if len(sys.argv) < 2:
    print 'Usage: const_output.py "command to watch"'
    sys.exit(1)

cmd_line = sys.argv[1:]

p = Popen(cmd_line)
p.communicate()[0]

使用示例:

跟踪路由:

> python const_output.py traceroute 10.0.0.38
traceroute to 10.0.0.38 (10.0.0.38), 30 hops max, 60 byte packets
 1  10.0.0.38 (10.0.0.38)  0.106 ms  0.023 ms  0.021 ms

平:

> python const_output.py ping 10.0.0.38
PING 10.0.0.38 (10.0.0.38) 56(84) bytes of data.
64 bytes from 10.0.0.38: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 10.0.0.38: icmp_seq=2 ttl=64 time=0.075 ms
64 bytes from 10.0.0.38: icmp_seq=3 ttl=64 time=0.076 ms
64 bytes from 10.0.0.38: icmp_seq=4 ttl=64 time=0.073 ms

> python const_output.py top
   # you will see the top output