JKKKKK44
← LIBRARY / 返回知识图书馆ENTRY / PYTHON-PORT-SCANNER
PROGRAMMING

Python 端口扫描器是怎么工作的

从 TCP 连接、超时和端口范围出发,拆解 Security Toolkit 中一个顺序端口扫描器的工作边界。

MATURITY
GROWING / 生长中
READING
约 2 分钟
UPDATED

端口扫描并不神秘:对 TCP 来说,最直接的做法就是依次尝试建立连接,再把成功建立连接的目标记为“开放”。Security Toolkit 的实现正是一个适合学习的最小版本——逻辑透明、行为可解释,也明确暴露了顺序扫描的成本。

从主机名到 IPv4 地址

输入可能是 localhost、域名或 IPv4 地址。程序先通过 socket.gethostbyname() 得到一个 IPv4 地址,再创建 AF_INET 与 SOCK_STREAM 组合的 TCP socket。这意味着当前实现没有处理 IPv6,也不会枚举一个域名背后的所有地址。

解析失败和连接失败应被区分:前者表示目标名称无法转换为地址,后者则只是某个端口没有在给定时间内完成连接。

connect_ex 返回了什么

Python 的 connect_ex((host, port)) 不会在普通连接失败时直接抛出异常,而是返回系统错误码。返回 0 代表 TCP 连接建立成功;其他值可能对应拒绝连接、超时或网络不可达。

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
    probe.settimeout(0.5)
    is_open = probe.connect_ex((address, port)) == 0

with 保证每次尝试结束后关闭 socket。否则扫描较大范围时,文件描述符会逐渐耗尽。

超时是一种取舍

超时过长会让不可达端口拖慢整个过程;超时过短又可能把高延迟网络中的开放端口判断为未开放。Security Toolkit 对普通范围使用约半秒超时,对一组常见端口使用更短的检查窗口。这是交互速度与准确性之间的工程取舍,不是协议保证。

由于实现按端口顺序逐个等待,最坏耗时近似为:

条件影响
端口数量增加总耗时近似线性增加
大量端口超时比立即拒绝连接更慢
网络延迟升高短超时更容易漏报

为什么要验证端口范围

TCP 与 UDP 端口号只有 0–65535,而面向用户的扫描通常将可用目标限制为 1–65535。程序还需要保证起始端口不大于结束端口。先验证输入可以避免创建无意义连接,也让错误信息比底层 socket 异常更清楚。

结果应该怎样理解

开放结果只说明三次握手在超时内完成。常见端口名称表可以提供“可能是 HTTP、SSH 或 DNS”的提示,但端口号不是服务身份。生产级工具还会考虑并发限制、服务探测、IPv6、速率控制和更细致的错误分类。

这个最小实现的价值在于把完整链路展示出来:解析地址、创建 socket、设置超时、尝试连接、解释返回码、关闭资源。理解这些步骤后,再讨论并发优化才有意义。