如何向异步socket函数传参并解决异步端口扫描阻塞问题
问题根因
你的代码实际还是同步串行执行,核心问题有两个:
- 你调用的是标准库
socket自带的阻塞式connect()方法,这个方法执行时会卡住整个线程,不会把执行权交还给asyncio事件循环。哪怕把它包在async def定义的协程里,运行时依然是一个连接跑完才会跑下一个,完全没有并发效果。 - 你全局只创建了1个socket实例,所有端口扫描任务共用这一个socket。而TCP连接本身是点对点的,单个socket同一时间只能维持一条连接,从逻辑上就不可能同时扫描多个端口。
正确实现方案
用asyncio原生提供的异步网络接口asyncio.open_connection替代阻塞的socket.connect,每个端口扫描任务独立处理连接,不要共用全局socket实例,修正后的代码如下:
import asyncio import time target = '72.221.171.130' t1 = time.time() async def connect(port): try: # 等待连接的过程会自动交还控制权给事件循环,不会阻塞其他任务 reader, writer = await asyncio.wait_for( asyncio.open_connection(target, port), timeout=2 ) print(f"端口{port}开放") # 用完及时关闭连接 writer.close() await writer.wait_closed() except Exception: # 连接超时、被拒绝直接跳过即可 pass async def main(): # 并发发起所有端口的扫描任务 tasks = [connect(port) for port in range(4100, 4150)] await asyncio.gather(*tasks) print(f'端口扫描耗时: {round((time.time() - t1),3)} 秒') if __name__ == "__main__": # Python3.7+ 直接用asyncio.run启动事件循环即可,无需手动获取loop asyncio.run(main())
这段代码的实际运行耗时基本等于你设置的连接超时时间,通常2-3秒就能扫完指定端口段,不会出现20秒串行等待的问题。
额外注意:
- 不要在asyncio协程里直接调用任何阻塞式IO方法,比如原生socket的收发接口、
requests库的HTTP请求、time.sleep()等。如果一定要用这类阻塞逻辑,需要用loop.run_in_executor把阻塞任务丢到独立线程池运行,否则会卡住整个事件循环,异步逻辑直接退化成串行同步。你之前测试requests、httpio时遇到的异步失效问题,本质也是这个原因:requests是纯阻塞实现,原生不支持asyncio调度,要做异步HTTP请求请选用aiohttp这类原生异步实现的库。- 异步函数传参逻辑和普通Python函数完全一致,支持位置参数、关键字参数、多参数传递,你之前代码里给
connect(port)传入端口参数的写法本身没有问题,性能问题和传参无关。
内容的提问来源于stack exchange,提问作者Istiak Mahmud
相关产品推荐
相关产品推荐

