当前位置:首页>python>【实战】Python 单进程多线程 TCP 端口并发检测实践指南

【实战】Python 单进程多线程 TCP 端口并发检测实践指南

  • 2026-10-11 06:30:25
【实战】Python 单进程多线程 TCP 端口并发检测实践指南

一、 业务背景

在系统运维与监控场景中,通常需要同时对 20 个以上的 TCP 端口进行连通性检测。传统的 Shell 脚本采用串行检测方式,不仅耗时较长,且在异常处理与日志记录方面表现欠佳。为此,本文采用 Python 的 threading 模块实现单进程多线程并发检测,以大幅提升检测效率并规范日志输出。

二、 核心技术模块

1. 多线程并发控制

由于多线程共享内存资源,数据同步是并发编程的关键。本方案采用“列表作为任务队列”的轻量级设计:

•将待检测的端口列表作为共享资源。•每个线程通过 list.pop() 方法获取任务,只要列表非空就持续弹出并处理,列表为空则自动退出。•使用 threading.Thread 创建线程,并通过 join() 方法阻塞主线程,确保所有子线程执行完毕后再进行后续逻辑。

优化建议:虽然列表 pop() 在 CPython 中由于 GIL(全局解释器锁)的存在是线程安全的,但在高并发或复杂场景下,更推荐使用 Python 内置的 queue.Queue 模块,它提供了更完善的线程安全机制。

2. 外部命令调用

使用 subprocess 模块调用系统命令(如 nc)进行端口探测。

•该模块可以捕获并抑制命令的标准输出,避免控制台信息杂乱。•通过 subprocess.call() 的返回值判断执行状态:返回 0 表示命令执行成功(即端口连通),非 0 表示失败。

3. 日志记录

使用 logging 模块替代 print,实现结构化的日志管理。

•支持设置日志级别(如 DEBUG, INFO, ERROR)。•支持自定义输出格式(包含时间、文件名、行号等)。•支持将日志持久化到文件,便于事后排查。

三、 源码实现

以下代码在原版基础上进行了现代化重构,兼容 Python 3,并增强了异常处理与代码规范:

#!/usr/bin/env python3# -*- coding:utf-8 -*-"""TCP 端口并发检测脚本依赖环境:需安装 netcat (nc) 组件,如: yum install -y nmap-ncat"""import subprocessimport threadingimport osimport logging# ================= 配置区 =================HOST_SERVER = 'localhost'PORT_LIST = [    9761, 9762, 9763, 9781, 9766, 9767, 9768, 9769, 9770, 9771,    8001, 8032, 8031, 8061, 8062, 8063, 8073, 8852, 8850, 8851, 8853, 8860]THREAD_COUNT = 10  # 并发线程数# 线程安全的结果收集列表port_alive = []port_unreacheable = []# 锁用于保护列表的写入操作result_lock = threading.Lock()# ================= 日志配置 =================def setup_logger(log_file):    logging.basicConfig(        level=logging.DEBUG,        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',        datefmt='%Y-%m-%d %H:%M:%S',        filename=log_file,        filemode='a+',        encoding='utf-8'  # Python3 推荐指定编码    )    return logging.getLogger('PortChecker')# ================= 核心检测逻辑 =================def is_reachable(port_list, host, logger):    """工作线程函数:循环从列表获取端口并检测"""    while True:        try:            # 线程安全地获取端口            with result_lock:                if not port_list:                    break                port = port_list.pop()        except IndexError:            break        try:            # 使用 nc 命令检测端口,超时设为 4 秒            cmd = ["nc", "-v", "-w", "4", "-z", host, str(port)]            ret_code = subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)            if ret_code == 0:                with result_lock:                    port_alive.append(port)                logger.info(f'端口: {port} 正常')            else:                with result_lock:                    port_unreacheable.append(port)                logger.error(f'端口: {port} 异常')        except Exception as e:            logger.error(f'端口: {port} 检测发生异常: {e}')# ================= 主程序入口 =================def main():    ab_path = os.path.abspath('./')    res_log = os.path.join(ab_path, 'xone_status.log')    logger = setup_logger(res_log)    # 复制一份端口列表用于 pop 操作,避免修改原始配置    task_queue = PORT_LIST.copy()    threads = []    for _ in range(THREAD_COUNT):        thr = threading.Thread(target=is_reachable, args=(task_queue, HOST_SERVER, logger))        thr.start()        threads.append(thr)    # 等待所有线程完成    for thr in threads:        thr.join()    logger.info(f"检测完成。正常: {len(port_alive)}, 异常: {len(port_unreacheable)}")    # 若存在异常端口,返回非零退出码,便于外部脚本捕获    if port_unreacheable:        exit(4)if __name__ == '__main__':    main()

四、 核心优化点说明

1.线程安全:引入了 threading.Lock()。虽然 list.pop() 在 CPython 中是原子的,但向 port_alive 追加数据以及判断列表是否为空的操作组合在一起时并非绝对安全,加锁可避免潜在的竞态条件。2.命令调用安全:将 subprocess.call 的字符串参数改为列表形式(如 ["nc", "-v", ...]),并设置 shell=False(默认值),这能有效防止命令注入风险,且避免了依赖 shell=True 带来的额外开销。3.输出抑制:使用 stdout=subprocess.DEVNULL 替代 shell=True 下的重定向,更加 Pythonic 且跨平台兼容性更好。4.Python 3 兼容:将 format() 字符串替换为 f-string,增加了 encoding='utf-8' 参数,确保日志写入不乱码。

五、 运行效果与日志分析

执行脚本后,可通过以下命令实时查看检测日志:

tail -f xone_status.log

预期日志输出示例:

2020-07-14 09:49:56 xone_check.py[line:68] INFO 端口:9781 正常2020-07-14 09:49:56 xone_check.py[line:68] INFO 端口:9770 正常2020-07-14 09:49:56 xone_check.py[line:73] ERROR 端口:8888 异常...

性能收益: 得益于多线程并发,20+ 个端口的检测耗时从串行模式的数十秒缩短至 1~2 秒内完成,显著提升了运维巡检效率。

最新文章

随机文章