【问题标题】:os.system("ping") call very slowos.system("ping") 调用很慢
【发布时间】:2017-02-17 00:42:29
【问题描述】:

我有以下脚本:

#!/usr/bin/env python3
import os

i = 1
while i != 255:
    Test = os.system("ping -c 1 10.0.0." + str(i) + " > /dev/null")
    if Test == 0:
        print("Host: 10.0.0." + str(i) + " is up!");
        i = i + 1
    else:
        i = i + 1

这是一个类似 NMap 的 python 脚本,我无聊并决定制作。

无论如何,当我运行它时,它非常慢,但是当我按住 CTRL + C 时,它运行得更快......而且它有效!

有没有办法让这个脚本变得更快?

【问题讨论】:

  • multiprocessing 将是一个开始的地方。顺便说一句,因为你的i 保证是数字的,所以这里是安全的,但是通常使用字符串连接来形成 shell 命令是非常不安全的。将数组传递给subprocess.Popen(将>/dev/null 重定向替换为不依赖于shell 的等价物,如stdout=open('/dev/null', 'wb'))是更好的形式。
  • 当然它会“超级慢” - ping 潜在主机然后等待响应需要时间,并且执行 255 次。如果您的系统上有nmap,您可以尝试使用:os.system("nmap -sP --max-retries=1 --host-timeout=500ms 10.0.0.{} > /dev/null".format(i)),而不是在 500 毫秒后放弃,但正如其他人建议的那样,如果您想让所有内容并行运行,则必须使用多处理。
  • @jersten, ...我不确定 GIL 在这里是否是个大问题,因为正在完成的工作正在等待子进程——等待本身应该在锁之外;只有在 SIGCHLD 进来时处理结果才应该严格要求持有锁。
  • 我宁愿避免使用NMap,我正在制作的程序应该像NMap,但更精简

标签: python ping


【解决方案1】:

默认情况下,ping 等待数据包到达 10 秒。由于许多地址不会被使用,或者拥有这些地址的计算机不会响应 ICMP 回显 (ping) 数据包,因此您将等待长达 2550 秒,或者如果某些地址引发响应,则等待时间会更短。

当您键入 Ctrl+C 时,您会发送一个 SIGTERM 信号,它会中止等待。如果在收到 ICMP 回显响应之前中止 ping,您将得到不正确的结果。由于本地网络非常快,因此您不太可能遇到这种情况。

为了加快速度,您可以通过两种方式修改您的方法:

  1. 在没有响应的情况下尽早放弃。传入-W 参数。例如,通过运行ping -c 1 -W 1 ...,ping 将只等待一秒钟,因此您的整个程序将花费大约 250 秒。
  2. 并行运行 ping。您可以手动执行此操作,通常使用线程/进程的Pool(或每个 ping 仅一个线程/进程)。请注意,您的操作系统可能会强制限制每秒的 ping 次数。例如,如果您将超时设置为 10 秒并设法同时运行所有 ping,那么您的程序将只需要 10 秒。

使用池的正确代码可能如下所示

import multiprocessing
import subprocess


TIMEOUT = 5  # in seconds
CONCURRENCY = 100  # how many pings in parallel?


def ping(ip):
    """ Returns true iff the host is reachable. """
    # print('ping %s' % ip)  # uncomment to see progress
    ret = subprocess.call(
        ['ping', '-W', str(TIMEOUT), '-c', '1', ip],
        stdout=subprocess.DEVNULL)
    if ret == 0:
        print('%s is reachable' % ip)

ips = ('10.0.0.%d' % i for i in range(1, 255))

with multiprocessing.Pool(CONCURRENCY) as p:
    p.map(ping, ips)

如果您不是在玩弄,您可能还想使用一个程序而不是并行运行的 ping。任何端口扫描器(例如nmap)都应该可以正常工作。

【讨论】:

  • 我对 python 很陌生,我将如何使用 Pool?我知道这不是你游泳的那个;)
  • @Python 跟随link to the documentation,它解释了如何使用池。如果您在阅读文档后有任何问题,feel free to ask them on stackoverflow.
  • 我有文档链接中的代码,但我应该把我的代码放在哪里?我很困惑XD
  • @Python 我添加了一个示例,说明您的代码如何使用池(以及正确的子进程调用)
【解决方案2】:

使用scapy。无需在 Python 线程中生成 ping 命令。

【讨论】:

  • 其实可能有——任何用户都可以ping通,但是你需要超级用户权限才能运行scapy。
  • 在 Linux 上,您只需要 CAP_NET_RAW 能力。
猜你喜欢
  • 1970-01-01
  • 2016-04-24
  • 1970-01-01
  • 2014-05-13
  • 2012-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多