You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python asyncio异步函数未异步执行?LAN端口扫描问题

问题:局域网TCP端口扫描任务无法并行执行

我想要快速扫描局域网(LAN),找到监听特定TCP端口(例如2442,即JS8Call网络API)的主机。我参考了Python asyncio异步执行教程的程序结构,程序虽能运行,但单个任务并未并行执行,而是串行运行——任务创建和结果收集看似正常,但运行时ping异步函数的打印信息按顺序出现,总是前一个超时后才出现下一个。我猜测ping函数未生成协程对象,请问该函数存在什么问题?

代码如下:

#!/usr/bin/python

import socket
import asyncio

socket.setdefaulttimeout(0.5)

async def ping(host, port):
  r = f'{host}:{port} OK'
  try:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
      s.connect( (host, port) )
      print( r )
      s.close()
      return r
  except Exception as X:
    print(f'{host} FAILED')
    return X

async def main():
  tasks = []
  async with asyncio.TaskGroup() as tg:
    # start all tasks
    for i in range(5,240):
      host = f'192.168.33.{i}'
      t = tg.create_task( ping(host, 22) )
      tasks.append(t)
  results = [ task.result() for task in tasks ]
  for p in results:
    if p != None:
      print(p)

asyncio.run( main() )

问题根源

你的ping函数虽被定义为async函数,但内部使用了同步阻塞的socket API——s.connect()是完全阻塞的调用,会卡住当前协程直到连接完成或超时,彻底剥夺了asyncio事件循环切换到其他协程的机会,最终导致所有任务只能串行执行。

你猜测的“ping函数未生成协程对象”是错误的:ping(host,22)确实返回了协程对象,tg.create_task也正确将其加入了任务组,问题核心出在函数内部的阻塞操作上。

解决方案

要实现真正的异步并行,必须使用asyncio提供的非阻塞网络API,替换同步的socket调用:

修改后的代码

#!/usr/bin/python

import asyncio

async def ping(host, port):
    result = f'{host}:{port} OK'
    try:
        # 使用asyncio的非阻塞TCP连接API
        reader, writer = await asyncio.open_connection(host, port)
        writer.close()
        await writer.wait_closed()
        print(result)
        return result
    except Exception as e:
        print(f'{host} FAILED')
        return e

async def main():
    tasks = []
    async with asyncio.TaskGroup() as tg:
        for i in range(5, 240):
            host = f'192.168.33.{i}'
            task = tg.create_task(ping(host, 22))
            tasks.append(task)
    # 筛选并打印成功结果
    results = [task.result() for task in tasks]
    for res in results:
        if isinstance(res, str) and 'OK' in res:
            print(res)

asyncio.run(main())

关键改动说明

  • 移除同步socket模块依赖,改用asyncio.open_connection()——这是原生支持异步非阻塞的TCP连接方法
  • 用await等待连接操作,此时事件循环会自动切换到其他就绪协程,实现真正的并行执行
  • 关闭连接时使用await writer.wait_closed(),确保异步关闭操作完成

修改后,所有扫描任务会并行执行,能大幅提升局域网端口扫描的速度。


内容的提问来源于stack exchange,提问作者Jindrich Vavruska

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:02:13