代码之家  ›  专栏  ›  技术社区  ›  Dave Forgac Eli Bendersky

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

  •  3
  • Dave Forgac Eli Bendersky  · 技术社区  · 17 年前

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

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

    但是,由于python不是以根用户身份运行,因此它无法打开在本机python中执行ping/traceroute所需的原始ICMP套接字。

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

    Ping a site in Python?

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

    以上所有示例都运行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 回复  |  直到 11 年前
        1
  •  6
  •   Alex Martelli    17 年前

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

        2
  •  4
  •   Community Mohan Dere    9 年前

    您应该阅读 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
    

    实际上,你所联系到的问题中的答案与你需要的非常接近。 Corey Goldberg's answer 使用管道和 readline 但是因为它和 -n 1 它的持续时间不足以产生影响。

        3
  •  1
  •   Thomas    17 年前

    您可以为子进程创建一个tty对并在其中运行。根据C标准(C99 7.19.3),标准输出的唯一时间是线路缓冲(而不是你说你不想要的完全缓冲)是在它是终端的时候。(或者显然是名为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函数而不是syscall。它只是更改当前进程输出的状态,当加载新的二进制文件时,将在exec调用中覆盖该状态。

        4
  •  1
  •   user59634    12 年前

    下面是另一种方法:

    # 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