我想要一种快速方法来检查 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
视频显示,单个失败的 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 会捕获更多。如果并行运行速度足够快,您可以考虑更多尝试。