ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python端口扫描器实战:TCP原理、并发控制与网络安全监控

Python端口扫描器实战:TCP原理、并发控制与网络安全监控 简介面向网络安全课程设计的一份端口扫描程序实现适合信息安全、网络工程等专业学生用于理解端口监控与扫描原理。程序基于MFC对话框框架开发支持对指定IP地址、指定端口及多线程并发扫描通过实际代码演示扫描任务调度、端口状态判断和结果反馈等关键环节并配有端口扫描原理说明帮助读者站在攻击者视角审视系统弱点从而强化本地安全防护意识。压缩包为rar格式共17个文件主要包括4个头文件、3个CPP源文件以及对话框资源、工程配置和图标等辅助模块整体仅29KB结构精简便于用Visual C 6.0打开并直接编译运行。目前已有235人学习下载适合作为课程设计参考或安全入门实验也可在此基础上扩展更多端口扫描策略与检测防护功能。1. 项目概述与核心需求1.1 从课程设计到实战工具这个项目到底在做什么终端监控和网络端口扫描这两个词放一起很多人第一反应是“这不就是黑客工具吗”。说实话我第一次拿到这个课程设计题目时也是这么想的但做着做着就发现端口扫描本身是中性技术关键在于怎么用、用在什么场景。企业里做安全运维的人每天都要扫端口资产管理、漏洞排查、合规检查哪一样都离不开它。课程设计选这个题目本质上是让你掌握网络通信的基本原理同时理解攻击者视角下的信息收集手段这样才能知道怎么防御。这个项目要解决的核心问题很简单在一台终端上通过编写代码实现对目标主机开放端口的探测判断目标机器上运行了哪些服务从而评估其暴露的攻击面。放在课程设计的语境里就是你得写一个能跑的扫描器能指定目标IP和端口范围能正确识别端口是开放、关闭还是被过滤最好还能给出对应的服务名称。适合谁来参考这个项目两类人。一类是正在做网络安全相关课程设计、毕业设计的在校生需要一份能讲清楚原理、能跑通演示的代码另一类是刚入门安全运维、想理解端口扫描原理的初学者想透过工具看本质。如果你只是想拿个现成脚本交差那这篇文也够用但我更希望你把它当成理解网络协议的敲门砖。1.2 项目设计的技术路线与预期成果整个项目我拆成了四个模块目标参数解析、端口探测引擎、结果分析与服务识别、报表输出。底层协议选TCP这是最常用也是最容易理解的。TCP端口扫描的核心思路就是利用TCP三次握手的过程来判断端口状态——你发一个SYN包过去对方回SYNACK说明端口开着回RST说明端口关了什么都不回可能是有防火墙过滤。编程语言我选了Python理由很直接上手快、网络编程库成熟、代码量少适合课程设计的时间节奏。当然你要是想炫技用Go写并发扫描性能会更好但那是后话先把Python版本跑通再说。预期成果是一份完整的扫描报告包含每个端口的状态、对应的服务名称、以及简单的风险提示。这个报告既要在终端里能看也要能导出成文件方便写课程设计报告时截图使用。下面这张图是我当初画的项目功能拆解你可以对照着自己调整输入参数模块目标IP、起始端口、结束端口、超时时间扫描引擎模块TCP连接探测、状态判断、并发控制结果分析模块服务指纹比对、端口状态归类、风险等级标记报表输出模块终端表格展示、文本文件导出2. 关键技术原理与工具选型解析2.1 TCP端口扫描的三种主流方式对比在写代码之前必须先把原理吃透否则你连扫描结果都解释不清楚。主流的TCP端口扫描方式有三种全连接扫描TCP Connect、半开扫描SYN Scan和TCP SYN半开扫描的进阶版。课程设计阶段我建议你用全连接扫描因为它不需要特殊的权限普通用户就可以跑而且逻辑最直观——就是完整地完成一次TCP三次握手。三次握手的流程大家都学过客户端发SYN包服务端回SYNACK包客户端再回ACK包。但端口扫描的时候情况就不一样了。如果你发的SYN包到达一个开放端口对方会正常回复SYNACK这时候你的扫描程序如果直接发ACK完成握手就叫做全连接扫描如果你收到SYNACK后立刻发RST包断开连接那就叫半开扫描。那RST是什么时候出现的呢有三种情况目标端口关闭时目标主机会直接回RST包目标防火墙规则拒绝时也可能回RST还有一种情况是你发送的SYN包本身有问题比如伪造了不存在的源IP目标主机也会回RST。理解这些状态码的含义是判断扫描结果的根基。半开扫描的优缺点也很明显。优点是不建立完整连接速度快、日志记录少是渗透测试中的首选缺点是要构造原始数据包Windows系统下需要管理员权限或使用NpcapLinux下需要root权限代码复杂度高。课程设计如果选半开扫描答辩时能加分但前提是你得把原理讲透。2.2 Python网络编程底层的核心机制Python做端口扫描最底层依赖的是socket模块它是对BSD Socket API的封装。在应用层看来你要做的事情就三步创建一个socket对象、调用connect方法去连目标地址、根据连接结果判断端口状态。这里有个关键细节connect方法是有超时机制的。默认情况下如果你连接一个不可达的IP地址socket会一直阻塞在那里等系统TCP超时通常是几分钟。所以扫描程序里必须设置settimeout把超时时间控制在一个合理的范围内比如1到3秒。超时时间设得太短容易漏报——网络稍微有点延迟就把正常开放的端口误判成关闭设得太长扫描速度太慢扫一个C段几百台机器得等到天荒地老。端口扫描并发的实现有两种常见思路。第一种是使用concurrent.futures的ThreadPoolExecutor创建线程池来并发执行扫描任务。Python的GIL对网络I/O操作影响不大因为socket操作在等待时会释放GIL所以线程池方案在扫描场景下效果很好。第二种是使用asyncio异步I/O效率更高但代码复杂度也更高对初学者不太友好。课程设计我推荐线程池简单高效代码量也少。还有个容易被忽视的点临时端口的选择。TCP连接时客户端会随机从系统分配的端口范围内选一个源端口。在Linux下这个范围由 /proc/sys/net/ipv4/ip_local_port_range 控制默认通常是 32768 到 60999。如果大量并发扫描可能导致临时端口耗尽报错信息通常是 “Cannot assign requested address”。所以并发数不是越大越好建议控制在 200 到 500 之间视操作系统和网络环境而定。2.3 终端监控与本项目的关系延伸回到“终端监控”这个词上来。课程设计题目里写的是“终端监控”我在实现时把监控拆成了两个维度一是对终端自身开放的端口进行监控即本机端口监听状态检测二是从终端发起对外部目标的扫描。前者是防御视角——检查自己的机器有没有意外开放的服务后者是攻击面评估视角——检查目标机器对外开放了哪些服务。我建议你在报告里把两个视角都提一下但代码实现还是聚焦在对外扫描上因为这是课程设计的核心考核点。接本机端口监听状态的检测方式比对外扫描还简单。用netstat -tlnp命令就能看到所有监听状态的TCP端口和对应的进程。代码层面可以调用psutil库的net_connections()方法拉取当前系统所有网络连接和监听端口信息。这部分代码可以作为项目的一个加分模块答辩时演示效果好而且代码量只需要十几行。3. 代码实现与核心环节拆解3.1 环境准备与依赖安装开发环境我建议用Python 3.8以上版本Windows和Linux都可以。模块方面标准库的socket、concurrent.futures、ipaddress是主力不需要额外安装第三方库就能跑通基础功能。如果你要加图形界面可以用tkinter也是标准库。创建虚拟环境是必须养成的习惯。Windows下在项目目录里执行python -m venv venv然后激活venv\Scripts\activate。Linux下是source venv/bin/activate。这样做的好处是项目依赖不会污染全局环境后续如果要装第三方库比如后续增强版本的python-nmap也能在隔离环境里管理。依赖清单很简单标准库即可。如果你计划扩展功能比如服务版本识别可以安装python-nmap库但它底层需要系统装了Nmap。就课程设计而言我强烈建议你只用标准库把代码逻辑吃透答辩时被问到细节也不会慌。3.2 核心扫描模块的完整代码与逐行注释先看整体结构分四个文件main.py入口和交互逻辑、scanner.py核心扫描引擎、analyzer.py结果分析与服务识别、reporter.py报表输出文件拆分是锻炼工程习惯的好机会。scanner.py 核心代码import socket import ipaddress def scan_port(target_ip, port, timeout2.0): 使用TCP全连接方式探测单个端口 参数 target_ip: 目标IP地址字符串格式 port: 目标端口整数 timeout: 超时秒数默认2秒 返回 True 表示端口开放False 表示端口关闭/过滤/不可达 # 创建TCP套接字 # AF_INET表示IPv4SOCK_STREAM表示面向连接的TCP协议 sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置超时时间避免connect方法无限期阻塞 sock.settimeout(timeout) result False try: # connect执行三次握手过程 # 如果端口开放握手成功函数正常返回 # 如果端口关闭对方会回RST抛ConnectionRefusedError异常 # 如果数据包被防火墙丢弃会抛socket.timeout异常 sock.connect((target_ip, port)) result True except socket.timeout: # 超时大概率是防火墙丢弃了SYN包端口处于filtered状态 result False except ConnectionRefusedError: # 端口关闭目标主机主动回RST包 result False except OSError as e: # 其他网络错误如IP不可达、主机不存在等 print(f[!] 目标 {target_ip}:{port} 网络异常: {e}) result False finally: # 无论什么情况最后都要关闭socket释放资源 sock.close() return result上面这段代码是全连接端口扫描的主干逻辑从网络编程角度看关键点是异常分类。初学者最容易犯的错误是只捕获一个Exception然后把所有失败都当作端口关闭这样会把“被防火墙过滤”和“端口确实关闭”混为一谈结果就失去了准确性。这里为什么要区分异常类型因为网络诊断需要你知道“不可达”和“被拒绝”是两种完全不同的问题。并发控制部分from concurrent.futures import ThreadPoolExecutor, as_completed def scan_port_range(target_ip, port_start, port_end, timeout1.0, max_workers300): 并发扫描指定端口范围 使用线程池控制并发数避免创建过多线程导致资源耗尽 返回值是一个生成器按完成顺序产出 (端口, 是否开放) 的结果 # 参数校检确保端口范围合法 if not (0 port_start 65535 and 0 port_end 65535): raise ValueError(端口范围必须在1-65535之间) if port_start port_end: port_start, port_end port_end, port_start results [] with ThreadPoolExecutor(max_workersmax_workers) as executor: # 提交所有任务到线程池 future_to_port { executor.submit(scan_port, target_ip, port, timeout): port for port in range(port_start, port_end 1) } # 按完成顺序收集结果 for future in as_completed(future_to_port): port future_to_port[future] try: is_open future.result() if is_open: results.append(port) # 实时输出方便观察扫描进度 print(f [] 发现开放端口: {port}) except Exception as e: print(f [-] 端口 {port} 扫描异常: {e}) return results这里有个性能的细节为什么不直接用executor.map而是用submit加as_completed因为map会按输入顺序返回结果但我们希望实时看到已扫描完成的结果as_completed是按任务完成顺序返回的体验更好尤其当扫描端口数量比较多时逐条即时刷新的输出比最后一次性打印更直观。线程池的核心原理是生产者-消费者模式。主线程作为生产者把N个扫描任务丢进线程池的队列工作线程作为消费者从队列里取任务执行。max_workers控制的是同时工作的线程数量它决定了系统资源的使用率和网络并发连接的峰值。建议从200开始调整观察你的终端卡不卡、网络有没有丢包再决定加大还是减小。main.py 入口代码import socket import sys import time from scanner import scan_port_range, scan_port def get_ip_from_host(host): 支持域名解析把用户输入的域名转为IP地址 比如输入 baidu.com解析出对应的IP try: # 这里会做DNS解析返回的是第一个IP地址 ip socket.gethostbyname(host) return ip except socket.gaierror: # DNS解析失败说明域名不存在或网络异常 print(f[!] 无法解析主机名: {host}) return None def parse_target(target): 解析目标参数支持三种形式 1. 单个IP: 192.168.1.1 2. IP段: 192.168.1.0/24 3. 域名: example.com # 如果包含 / 说明是IP段CIDR表示法 if / in target: # 导入ipaddress模块做CIDR展开 import ipaddress try: network ipaddress.ip_network(target, strictFalse) # 生成器方式逐个产出IP避免网络地址和广播地址 return [str(ip) for ip in network.hosts()] except ValueError: print(f[!] 无效的IP段格式: {target}) return None # 如果包含字母说明是域名 elif any(c.isalpha() for c in target): ip get_ip_from_host(target) return [ip] if ip else None else: # 单个IP地址 try: ipaddress.ip_address(target) return [target] except ValueError: print(f[!] 无效的IP地址格式: {target}) return None def single_target_mode(target_ip): 单目标扫描模式扫描常用端口和指定端口范围 print(f\n[] 开始扫描目标: {target_ip}) print(f[] 目标IP校验: {target_ip}) # 常用服务端口快速扫描 common_ports { 21: FTP, 22: SSH, 23: Telnet, 25: SMTP, 53: DNS, 80: HTTP, 110: POP3, 135: RPC, 139: NetBIOS, 143: IMAP, 443: HTTPS, 445: SMB, 993: IMAPS, 995: POP3S, 1433: MSSQL, 1521: Oracle, 3306: MySQL, 3389: RDP, 5432: PostgreSQL, 6379: Redis, 8080: HTTP-Alt, 8443: HTTPS-Alt, 9200: Elasticsearch } start int(input([] 输入起始端口 (默认1): ) or 1) end int(input([] 输入结束端口 (默认1024): ) or 1024) timeout float(input([] 设置超时秒数 (默认2.0): ) or 2.0) # 选择扫描方式 print(\n[] 选择扫描模式:) print( 1. 仅扫描常用端口) print( 2. 扫描自定义范围) mode input([] 请选择 (默认1): ) or 1 print(f\n[] 扫描进度: 目标 {target_ip}, 端口范围 {start}-{end}, 超时 {timeout}s) start_time time.time() if mode 1: open_ports [] for port, service in common_ports.items(): if scan_port(target_ip, port, timeout): open_ports.append((port, service)) print(f [] {port:5}/tcp {service}) open_ports.sort() if not open_ports: print( [-] 未发现开放端口) else: open_ports scan_port_range(target_ip, start, end, timeout) elapsed time.time() - start_time print(f\n[] 扫描完成耗时 {elapsed:.2f} 秒发现 {len(open_ports)} 个开放端口) return open_ports def main(): 程序入口处理用户输入和整体流程 banner r Network Port Scanner v1.0 网络端口扫描终端监控工具 print(banner) target input([] 请输入目标IP地址或域名: ).strip() if not target: print([!] 目标不能为空) return targets parse_target(target) if not targets: return # 批量扫描模式支持IP段 if len(targets) 1: print(f[] 检测到 {len(targets)} 个目标地址使用批量扫描模式) all_results {} start_time time.time() for ip in targets: print(f\n[] 正在扫描 {ip} ) open_ports single_target_mode(ip) all_results[ip] open_ports elapsed time.time() - start_time print(f\n[] 批量扫描全部完成总耗时 {elapsed:.2f} 秒) # 生成汇总报告 print(\n[] 扫描汇总 ) for ip, ports in all_results.items(): if ports: print(f {ip}: {len(ports)} 个开放端口 - {ports}) else: print(f {ip}: 未发现开放端口) else: # 单目标扫描 single_target_mode(targets[0]) if __name__ __main__: try: main() except KeyboardInterrupt: # 按CtrlC优雅退出 print(\n[!] 用户中断扫描程序退出) sys.exit(0)上面这段代码是入口与交互层做了三件事解析用户输入的目标、管理扫描流程、实时打印结果。设计上single_target_mode函数处理单目标的交互逻辑main函数负责总控调度这样代码组织清晰答辩时也容易讲清楚结构。3.3 超时时间的计算逻辑与调优思路超时时间的选择直接影响扫描结果和速度。我在实际测试中总结了一套经验值局域网内扫描比如192.168.x.x网段超时设 0.3 到 0.5 秒就够了因为内网延迟在1ms级别留 300ms 的余量绰绰有余公网扫描设 2 到 3 秒比较稳妥因为公网跳数多、延迟大某些跨国线路RTT可能到几百毫秒如果目标是国外服务器且网络状况一般可以放宽到 5 秒。超时时间与总耗时的关系大致是总耗时 ≈ 超时时间 × 关闭/过滤端口数量 / 并发线程数。举个例子你扫1到1024端口假设一半端口是关闭的超时设2秒并发300线程那理论耗时是 512 × 2 / 300 ≈ 3.4秒。当然这是最粗略的估算实际还要算上网络往返时间和任务调度开销但量级差不多。有个提升效率的小技巧实际扫描时可以先快速扫一遍常用端口20个左右如果有开放的再针对性地扫全端口范围。这样大部分场景下几秒钟就能得出结论而不是一开始就扫65536个端口。4. 实操演示与扫描结果分析4.1 完整运行过程实录我拿自己局域网里一台测试机做演示IP是192.168.31.187上面跑了SSH、HTTP和MySQL服务。执行python main.py输入目标IP模式选1常用端口快速扫描运行结果如下 Network Port Scanner v1.0 网络端口扫描终端监控工具 [] 请输入目标IP地址或域名: 192.168.31.187 [] 开始扫描目标: 192.168.31.187 [] 目标IP校验: 192.168.31.187 [] 输入起始端口 (默认1): [] 输入结束端口 (默认1024): [] 设置超时秒数 (默认2.0): 0.5 [] 选择扫描模式: 1. 仅扫描常用端口 2. 扫描自定义范围 [] 请选择 (默认1): 1 [] 扫描进度: 目标 192.168.31.187, 端口范围 1-1024, 超时 0.5s [] 22/tcp SSH [] 80/tcp HTTP [] 3306/tcp MySQL [] 扫描完成耗时 1.82 秒发现 3 个开放端口多快从输入到输出结果不到2秒。这就是并发扫描的优势。如果把超时时间设成默认的2秒理论上耗时也才几秒但如果你扫描的是公网地址这个差距会被放大到几十倍。再看一个公网扫描的例子。我扫描一个位于国外的测试服务器只扫常见端口超时设3秒。结果会怎样部分端口会出现超时filtered状态部分端口能正常识别。这时候你就知道扫描结果不能光看“开”和“关”还有一种状态叫“过滤/不可达”在实际的安全评估里这种状态同样有意义——说明中间可能有防火墙在拦截。4.2 结果解读与服务识别拿到扫描结果关键一步是把端口号映射到对应的服务名称和潜在风险。我在代码里维护了一个常用端口字典但实际场景中端口号和服务并不能完全划等号比如8080端口可能是HTTP备用端口、可能是Tomcat管理器、也可能是某个API服务。要准确识别得做服务指纹比对就是给端口发送特定的探测数据包根据返回的Banner信息判断具体服务版本。用一个具体的例子来说明端口服务的差异同样是80端口一台是Nginx另一台是IIS返回的HTTP响应头完全不同。Nginx会返回Server: nginx/1.18.0IIS会返回Server: Microsoft-IIS/10.0。通过Banner识别你能知道服务的具体类型和版本这对后续漏洞排查太重要了。不过课程设计阶段做到端口映射到常见服务这一步就够了。我在结果输出里给每个开放端口加了一个风险等级标记。等级划分规则很简单你可以在analyzer.py里自己实现风险等级判定规则示例高远程管理端口暴露且无访问控制22、3389、5900 对外开放中数据库端口暴露3306、1433、1521低Web服务端口或通用端口80、443、8080信息其他非常见端口3000、5000、9000 等开发端口5. 常见问题排查与性能调优实录5.1 Windows环境下的报错与解决方案很多同学用的是Windows系统来做课程设计实际运行时会遇到一个特有的大坑防火墙拦截本地扫描请求。情况是这样的你写了代码跑起来发现所有端口都显示关闭但同一台机器上你用Nmap扫描却能正常出结果。原因往往在于Windows Defender防火墙默认阻止了Python进程的入站连接。这是出站连接不受影响所以你的请求能发出去但目标机器的回应被本机防火墙拦了你收不到SYNACK包就误判成端口关闭。解决方法是临时关闭防火墙或者在防火墙的入站规则里为python.exe添加允许规则。我建议用后者关了防火墙容易被答辩时的演示环境坑到。还有一个常见问题是[WinError 10049] 请求的地址在其上下文中无效。这通常是因为你输入的IP格式不对socket底层没法绑定。比如输入了 999.999.1.1或者输入了带空格的字符串忘了strip。所以我在代码里用了ipaddress模块做校验能拦截大部分非法输入。5.2 扫描速度优化的实战调参记录我用一个实验数据说明调参的影响。目标某公网服务器扫描1-1000端口。测试环境家用宽带下行100M上行30M本机6核CPU。第一轮timeout3.0max_workers200耗时约15秒。 第二轮timeout1.0max_workers200耗时约8秒。 第三轮timeout1.0max_workers500耗时约6秒。 第四轮timeout0.5max_workers500耗时约4秒但出现2个端口可能是误报连接超时误判为关闭。结论timeout从3改成1成本最低、收益最明显max_workers从200加到500收益有限且可能造成源端口耗尽。建议课程设计场景timeout设1秒max_workers设300为基准根据实际网络微调。关于并发数的上限还有个底层限制Linux下每个连接的源端口范围有限如果并发太高新连接无法分配源端口报错Cannot assign requested address。遇到这个情况用sysctl net.ipv4.ip_local_port_range查看当前范围如果太小可以调大但课程设计里把并发控制在300左右就够用了。5.3 结果漂移与误报处理端口扫描的误报和漏报问题是安全测试中非常实际的一个话题。误报说的是把本来关闭的端口报告成开放漏报是把开放端口忽略了。我做了几组对照实验发现最大的干扰因素来自两个地方。第一是防火墙的RST注入。某些安全设备会假装目标主机回应RST包来干扰扫描让扫描器误以为端口关闭。这种设备的行为很难用代码层面解决常规做法是多次扫描取交集或者用不同扫描方式交叉验证。第二是目标主机的连接速率限制。如果目标配置了iptables的limit模块超过阈值后直接丢弃新连接请求你的扫描就会大量超时。这同样需要重复探测来验证。所以在代码里可以加一个“双重探测”开关对第一次判断为开放的端口再连接一次确认。代价是多花一次握手时间换来的是一份更可信的扫描报告。实际操作中值得开。5.4 典型排查速查表现象可能原因排查方案所有端口都显示关闭本地防火墙拦截回包检查Defender或iptables规则放行python进程大量端口超时目标防火墙丢弃SYN调大thread超时时间到3秒再试崩溃 TypeError: argument of type ‘int’ is not iterable端口参数传了数字类型循环里用了字符串比较检查端口类型统一用int[Errno 98] Address already in use并发过多临时端口被占满调低max_workers或等待端口释放反病毒软件报毒扫描行为被特征识别课程设计场景可临时退出反病毒软件并向老师说明DNS解析缓慢系统DNS配置异常手动传入IP地址绕过解析还有个细节用ThreadPoolExecutor的as_completed收集结果时不要在里面做打印之外的耗时操作比如文件写入否则会把线程池的IO阻塞串行化拖慢整体速度。打印虽然也有GIL锁但输出频率不高时影响可忽略。6. 扩展方向与我的实操心得6.1 从全连接到SYN半开扫描的演进策略如果你想让课程设计更有含金量我强烈建议在完成全连接扫描后再实现一个半开扫描的模块。半开扫描基于raw socket用Scapy库构造SYN包并监听响应。思路是发送SYN包后等待监听端的响应如果捕获到SYNACK包说明端口开放捕获到RST包说明端口关闭。关键点是收到SYNACK后要立刻发送RST包断开连接这样目标主机不会记录完整的连接日志又节约了资源。用Scapy实现半开扫描的核心代码思路如下from scapy.all import IP, TCP, sr1, conf conf.verb 0 # 关闭Scapy的详细输出 def syn_scan(target_ip, port, timeout2): # 构造IP包和TCP包flags设为S表示SYN packet IP(dsttarget_ip) / TCP(dportport, flagsS) response sr1(packet, timeouttimeout) if response is None: return filtered # 超时无响应可能被防火墙过滤 elif response.haslayer(TCP): if response.getlayer(TCP).flags 0x12: # SYNACK # 收到开放确认发送RST断开 rst_packet IP(dsttarget_ip) / TCP(dportport, flagsR) send(rst_packet) return open elif response.getlayer(TCP).flags 0x14: # RST return closed return unknown这个模块的难度集中在raw socket的权限问题上。Windows下需要管理员权限运行Linux下需要root权限。如果你在课程设计里能演示半开扫描并把和全连接扫描的对比速度差异、目标日志差异讲明白答辩时绝对是个加分项。6.2 部分截图与实际操作中的经验教训最后说说我在实际调试中掉过的坑算是给后人留个路标。第一个坑是全局变量污染。我第一版代码把所有扫描结果放在一个全局列表里多线程并发append结果Python的list是线程安全的但如果你同时做sort或remove操作就可能在极端情况下出现数据竞争。解决方法是避免共享可变状态要么用局部变量收集结果要么用queue.Queue或concurrent.futures的返回值来传递数据。第二个坑是用户输入的合法性校验。初期我没有加IP格式校验用户输入192.168.1这种不完整的地址socket的connect直接抛OSError: [Errno 22] Invalid argument报错信息极其不友好。加了ipaddress模块校验后错误提示清晰多了也避免了后续流程的崩溃。第三个很重要的经验运行完后被扫描的目标主机/安全设备会记录你的扫描行为不要用这个工具去扫描未经授权的公网主机。这既是安全合规问题也是一个从业者最基本的职业底线。我上课时跟学生说扫描器就像一把手术刀临床手术能救命乱捅人就是犯罪。课程设计阶段自己搭个虚拟机环境或者在自己局域网内测足够了。如果你想让项目继续深化还可以做这几个点把扫描结果导出成CSV或HTML报告、增加命令行参数解析支持python main.py -i 192.168.1.1 -p 1-1024 -t 1这样的写法、把服务和CVE漏洞库关联做简单漏洞提示。甚至可以把终端监控能力扩展一下扫描结果与本地进程关联给出每个端口对应的本地进程名称和PID——这就是一个迷你版的资产管理工具了。本文还有配套的精品资源点击获取
返回列表