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

2024-06-16 12:13:24 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

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

这使我回到使用系统的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,

Tags: or方法命令child示例lineshellping
3条回答

您应该阅读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,因此它不会持续足够长的时间来产生影响。

pexpect是我在“默认情况下”为像您这样的任何需求所追求的——还有其他类似的模块,但是pexpect几乎总是最丰富、最稳定、最成熟的模块。如果我也必须在Windows下正确运行(ping和traceroute可能也有自己的问题),我会费心寻找替代方案——如果是这样,请告诉我们,我们会看看能安排什么!-)

您可以为子流程创建一个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()将not起作用,因为setvbuf()是libc函数,而不是syscall。它只是改变当前进程输出的状态,当加载新的二进制文件时,它将在exec调用中被覆盖。

相关问题 更多 >