satyamsingh12345/port-scanner
GitHub: satyamsingh12345/port-scanner
一个基于 Python 标准库构建的轻量级多线程 TCP 端口扫描器,通过并发连接探测目标主机端口状态并自动记录日志。
Stars: 0 | Forks: 0
# port-scanner
一个使用 Python 构建的多线程 TCP 端口扫描器 —— 可以扫描单个主机或端口范围,将结果分类为 open/closed/timeout,并将所有内容记录到控制台和文件中。旨在学习 socket 编程和并发。
# TCP 端口扫描器
一个使用 Python 编写的轻量级、多线程 **TCP 端口扫描器**。作为一个实践项目构建,用于学习 **socket 编程** 和 **并发** (线程)基础知识 —— 这些是网络安全和 SOC 分析师工作的核心技能。
## 目录
- [功能](#features)
- [工作原理](#how-it-works)
- [项目结构](#project-structure)
- [环境要求](#requirements)
- [安装说明](#installation)
- [使用说明](#usage)
- [示例](#examples)
- [输出示例](#sample-output)
- [日志记录](#logging)
- [错误处理](#error-handling)
- [法律 / 道德声明](#legal--ethical-notice)
- [我的学习心得](#what-i-learned)
- [可能的改进](#possible-improvements)
- [许可证](#license)
## 功能
- 扫描**单个主机**的某个端口、端口列表或整个端口范围。
- 使用 **多线程** (`ThreadPoolExecutor`) 扫描,可快速获得数百个端口的扫描结果。
- 将每个端口分类为 **open**、**closed** 或 **timeout/error**。
- 尝试识别 open 端口的常见服务名称(例如 `80 → http`)。
- 将结果记录到 **控制台和带有时间戳的日志文件中**。
- 支持自定义超时时间和线程数。
- 能够优雅地处理不可达主机、DNS 解析失败和 `Ctrl+C` 中断。
## 工作原理
扫描器使用 Python 内置的 `socket` 模块尝试与每个目标端口建立 TCP 连接:
1. 为目标 IP 和端口创建一个 TCP socket。
2. `connect_ex()` 尝试进行 TCP 三次握手,但不会在失败时引发异常(这与 `connect()` 不同),这使得它非常适合用于扫描大量端口。
3. 返回值为 `0` 表示端口 **open**(连接成功)。任何其他值都表示端口 **closed** 或主动拒绝连接。
4. 每个端口都在各自的线程中进行扫描,并提交给 `concurrent.futures.ThreadPoolExecutor`,因此可以并行检查数百个端口,而不是逐个检查。
5. `threading.Lock` 可防止多个线程同时写入控制台/日志而导致输出混乱。
## 项目结构
```
port-scanner/
├── port_scanner.py # Main script — all scanning logic and CLI
├── requirements.txt # Dependencies (none beyond the standard library)
├── logs/ # Auto-created; timestamped scan logs land here
│ └── .gitkeep
├── LICENSE
├── .gitignore
└── README.md
```
## 环境要求
- Python **3.8+**
- 无需第三方包 —— 使用的所有模块(`socket`、`threading`、`argparse`、`logging`、`concurrent.futures`)都是 Python 标准库的一部分。
## 安装说明
```
git clone https://github.com//port-scanner.git
cd port-scanner
```
不需要执行 `pip install` 步骤,但为了完整性及满足未来的依赖需求,项目中仍包含了 `requirements.txt` 文件。
## 使用说明
```
python port_scanner.py -H [-p ] [-t ] [-T ]
```
### 参数
| 标志 | 完整形式 | 描述 | 默认值 |
|------|--------------|-------------------------------------------------------------------|------------|
| `-H` | `--host` | 目标主机名或 IP 地址(**必填**) | — |
| `-p` | `--ports` | 要扫描的端口 —— 单个、逗号分隔列表、范围或混合形式 | `1-1024` |
| `-t` | `--timeout` | 每个连接的超时时间(秒) | `1.0` |
| `-T` | `--threads` | 最大并发线程数 | `100` |
### `--ports` 接受的端口格式
| 格式 | 示例 | 含义 |
|-----------------|-------------------|------------------------------------|
| 单个端口 | `80` | 仅扫描端口 80 |
| 逗号分隔列表 | `22,80,443` | 仅扫描这些指定端口 |
| 范围 | `1-1024` | 扫描从 1 到 1024 的每一个端口 |
| 混合 | `22,80,1000-1010` | 组合使用列表和范围 |
## 示例
使用默认参数扫描主机的前 1024 个端口:
```
python port_scanner.py -H scanme.nmap.org
```
使用较短的超时时间和更多线程扫描特定范围:
```
python port_scanner.py -H 192.168.1.1 -p 1-65535 -t 0.5 -T 200
```
仅扫描少数知名端口:
```
python port_scanner.py -H example.com -p 22,80,443,3306
```
## 输出示例
```
Log file: logs/scan_20260727_094200.log
============================================================
Target : scanme.nmap.org (45.33.32.156)
Ports : 1024 total
Timeout : 1.0s Threads: 100
Started : 2026-07-27 09:42:00
============================================================
[OPEN] Port 22 (ssh)
[OPEN] Port 80 (http)
============================================================
SCAN SUMMARY
Open : [22, 80]
Closed : 1020 ports
Timeouts: 2 ports
Errors : 0 ports
Duration: 4.87s
============================================================
```
## 日志记录
每次运行都会在 `logs/` 目录中生成一个带有时间戳的新文件,例如 `logs/scan_20260727_094200.log`。日志文件包含与打印到控制台完全相同的信息:扫描配置、发现的每个 open 端口、任何超时/错误以及最终摘要。这方便您保留过去扫描的记录,或将其附加到报告中。
## 错误处理
扫描器被设计为优雅地失败,而不是直接崩溃:
- **无法解析的主机名** (`socket.gaierror`) → 打印明确的致命错误并退出,而不是抛出 traceback。
- **连接超时** → 该端口将被记录为 `timeout`,扫描继续进行。
- **其他 socket 错误**(例如网络不可达) → 该端口会被记录为 `error`;其余的扫描不受影响。
- **扫描期间按下 Ctrl+C** → 会被捕获并报告为扫描被中断,而不是显示原始的堆栈跟踪。
- **无效的 `--ports` 输入**(例如 `abc`、反向的范围) → 在任何扫描开始之前都会被捕获并报告。
## 法律 / 道德声明
仅扫描您 **拥有** 或已获得 **明确书面许可** 进行测试的主机和网络。未经授权的端口扫描可能会违反法律(如美国《计算机欺诈和滥用法》或其他地区的类似立法),并且也可能违反 ISP 或云服务提供商的可接受使用政策。`scanme.nmap.org` 由 Nmap 项目提供,专门用于安全、合法的扫描练习。
## 我的学习心得
- 从客户端 socket 的角度来看,TCP 三次握手是如何进行的,以及在扫描用例中 `connect_ex()` 与 `connect()` 有何不同。
- 如何使用 `ThreadPoolExecutor` 对 I/O 密集型工作进行并行化,而不是手动管理线程。
- 当许多线程并发写入时,为什么共享输出(控制台/日志)需要加锁。
- 使用 `argparse` 构建 CLI 工具,包括为灵活的 `--ports` 格式添加自定义验证。
- 设计日志记录机制,使相同的输出在实时(控制台)和事后(日志文件)都能发挥作用。
## 可能的改进
- 添加 UDP 扫描支持。
- 为 open 端口添加 banner grabbing 功能(读取服务的欢迎消息)。
- 将结果导出为 JSON/CSV 格式,以便更容易地与其他工具集成。
- 使用精选的最常见 open 端口列表,添加 `--top-ports` 模式,而不是使用完整范围。
- 使用 `asyncio` 实现异步版本,以便与多线程方法进行对比。
## 许可证
该项目基于 [MIT 许可证](LICENSE) 授权。
标签:Python, TCP/IP, 后端开发, 插件系统, 数据统计, 无后门, 端口扫描, 网络工具, 逆向工具