使用asyncio实现局域网在线主机检测报错:期望协程却得到True
问题分析与修正方案
错误原因
你调用asyncio.create_task()时传入的是普通函数的执行结果(pinger(ip)会立即执行并返回True或None),但create_task要求传入的是协程对象(用async def定义的函数调用后返回的对象),这直接触发了TypeError。
另外,原代码里的subprocess.check_call是同步阻塞调用,就算改成协程,也会卡住整个asyncio事件循环,完全发挥不了异步的优势。
修正后的代码
#!/usr/bin/env python3 import asyncio import socket import subprocess def get_my_ip(): """获取本机IP,生成局域网网段前缀""" s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # 连接公共DNS,确保能获取本机正确IP s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] print(f"My ip is: {ip}") return ip finally: s.close() async def pinger(ip): """异步执行ping检测,返回存活IP""" try: # 使用asyncio异步子进程,避免阻塞事件循环 proc = await asyncio.create_subprocess_exec( 'ping', '-c1', '-W1', # -W1设置超时1秒,加快检测速度 ip, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) await proc.wait() if proc.returncode == 0: print(f"✅ {ip} 存活") return ip except Exception: pass return None async def main(): pool_size = 255 start = 102 # 生成局域网网段前缀,比如192.168.1. ip_parts = get_my_ip().split('.') base_ip = '.'.join(ip_parts[:3]) + '.' # 创建所有ping任务 tasks = [pinger(f"{base_ip}{i}") for i in range(start, pool_size+1)] # 等待所有任务完成,过滤掉None(即未存活的IP) alive_ips = [ip for ip in await asyncio.gather(*tasks) if ip] print("\n=== 存活主机列表 ===") for ip in alive_ips: print(ip) if __name__ == "__main__": asyncio.run(main())
关键改动说明
- 把
pinger改成async def定义的协程函数,调用后返回协程对象,符合asyncio的要求(asyncio.gather可直接接收协程对象,无需手动调用create_task)。 - 替换同步的
subprocess.check_call为异步的asyncio.create_subprocess_exec,配合await proc.wait()让ping操作在后台执行,不阻塞其他任务。 - 给ping命令增加
-W1参数设置超时1秒,大幅提升检测效率。 - 使用
subprocess.DEVNULL替代手动打开/dev/null,更简洁安全。 - 收集并过滤出所有存活的IP,让结果更直观。
内容的提问来源于stack exchange,提问作者Ciasto piekarz
相关产品推荐
相关产品推荐

