检查网络上的计算机是否处于睡眠状态而不唤醒它(Python)

问题描述 投票:0回答:1

我想要一种快速方法来检查 LAN 上的计算机是否已唤醒或未给出其 IP 地址(在 Windows 上)而不唤醒它。我写了以下内容,有效:

def is_awake(ipOrName, timeout=0.05):
  try:
    tt = round(timeout*1000)
    cmdargs = ["ping", "-n", "1", "-w", f'{tt}', "-a", ipOrName]
    result = subprocess.run(cmdargs, capture_output=True, text=True)
    if "Received = 1" in result.stdout:
      return True
    else:
      return False
  except Exception as e:
    print(f"Error checking IP reachability: {e}")
    return False

但我注意到,当运行它来顺序检查大量 IP 地址(例如 30 个)时,这可能会非常慢。我可以将 print 语句添加到代码中,并在

subprocess.run()
行之前和之后看到关闭的计算机的可见延迟(对于与打开的计算机对应的 IP 来说,这基本上是即时的)。似乎超时参数没有得到尊重,或者可能还有其他原因导致
subprocess.run()
函数需要很长时间才能返回。我不确定。

有没有更好的方法来做到这一点?下面的方法要快得多,但我无法使用它,因为它会将计算机从睡眠中唤醒:

def is_reachable(ipOrName, port = 445, timeout=0.05):
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.settimeout(timeout)
  try:
    s.connect((ipOrName, int(port)))
    s.shutdown(socket.SHUT_RDWR)
    return True
  except:
    return False
  finally:
    s.close()

有什么想法吗?

该视频演示了我的第一种方法有多慢: https://www.youtube.com/shorts/SZSMOucKiuQ

python windows ip-address sleep-mode wakeup
1个回答
0
投票

视频显示,单个失败的 ping 在大约预期时间内完成,但由于每个 ping 都是串行完成的,因此聚合时间相对较长。 “相对”是因为这在很多情况下是完全可以接受的。

您可以并行化这些 ping。您当前的函数仅处理单个 ping,因此我必须编写另一个处理多个 ping 的函数。在第一种情况下,您可以使用线程池

import multiprocessing.pool.ThreadPool as ThreadPool
import functools

def is_awake(ipOrName, timeout=0.05):
  try:
    tt = round(timeout*1000)
    cmdargs = ["ping", "-n", "1", "-w", f'{tt}', "-a", ipOrName]
    result = subprocess.run(cmdargs, capture_output=True, text=True)
    if "Received = 1" in result.stdout:
      return True
    else:
      return False
  except Exception as e:
    print(f"Error checking IP reachability: {e}")
    return False
    
def many_are_awake(ipOrNameList, timeout=0.05):
    worker = functools.partial(is_awake, timeout=timeout)
    with ThreadPool(len(ipOrNameList)) as pool:
        result = pool.map(worker, ipOrNameList)
    return result

但是由于 ping.exe 已经是一个单独的进程,因此您可以使用

Popen
而不是
run
,它不会等待一个 ping 完成后再开始下一个。

def many_are_awake(ipOrNameList, timeout=0.05):
  try:
    tt = round(timeout*1000)
    procs = []
    for ipOrName in ipOrNameList:
      cmdargs = ["ping", "-n", "1", "-w", f'{tt}', "-a", ipOrName]
      proc = subprocess.Popen(cmdargs, stdout=subprocess.PIPE,
          stderr=subprocess.STDOUT))
      procs.append(proc)
    results = []
    for proc in procs:
      stdout, stderr = proc.communicate()
      results.append("Received = 1" in stdout)
    return results
  except Exception as e:
    print(f"Error checking IP reachability: {e}")
    return []

顺便说明一下,超时时间较短的单次 ping 有时会给您带来误报。至少有几秒超时的多次 ping 会捕获更多。如果并行运行速度足够快,您可以考虑更多尝试。

© www.soinside.com 2019 - 2024. All rights reserved.