快速识别可访问端口号:Python 实现端口扫描
快速识别可访问端口号:Python 实现端口扫描
目录
- 背景与需求
- 实现思路
- 代码实现
- 基础版:单线程扫描
- 优化版:多线程扫描
- 代码优化与性能提升
- 总结与扩展
背景与需求
在网络安全、系统监控或网络管理中,快速识别目标主机的开放端口是一项常见任务。开放的端口通常意味着主机上运行着某种服务,例如 HTTP(80 端口)、HTTPS(443 端口)、SSH(22 端口)等。
Python 提供了强大的网络编程能力,可以通过 socket
模块实现端口扫描。本文将介绍如何使用 Python 快速识别目标主机(例如 114.66.41.155
)的开放端口,并提供两种实现方式:基础的单线程扫描和优化的多线程扫描。
实现思路
核心思想
-
建立 TCP 连接:
- 使用
socket.socket()
创建一个 TCP 套接字。 - 调用
connect_ex()
方法尝试连接目标 IP 的指定端口。 - 如果返回值为
0
,表示端口开放;否则,表示端口关闭或无法访问。
- 使用
-
扫描范围:
- 端口号的范围是
1
到65535
,可以覆盖所有可能的 TCP 端口。 - 为了提高效率,可以先扫描常用端口(如
1-1024
),再扩展到其他端口。
- 端口号的范围是
-
性能优化:
- 使用多线程或异步 I/O 提高扫描速度。
- 设置合理的超时时间,避免因部分端口长时间未响应而影响整体效率。
代码实现
基础版:单线程扫描
以下是一个基础的单线程端口扫描实现:
import socket# 设置目标 IP 地址
target_ip = "114.66.41.155"# 定义需要扫描的端口范围
start_port = 1
end_port = 1024 # 可以根据需要调整范围# 创建一个列表来存储开放的端口
open_ports = []# 定义端口扫描函数
def scan_port(port):try:# 创建一个 socket 对象sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.settimeout(1) # 设置超时时间为 1 秒result = sock.connect_ex((target_ip, port))if result == 0:print(f"端口 {port} 是开放的")open_ports.append(port)sock.close()except Exception as e:print(f"扫描端口 {port} 时发生错误: {e}")# 扫描端口
def scan_ports():for port in range(start_port, end_port + 1):scan_port(port)# 执行端口扫描
if __name__ == "__main__":print(f"正在扫描目标 IP {target_ip} 的端口...")scan_ports()print(f"\n扫描完成,开放的端口:{open_ports}")
代码说明
socket.socket()
:创建一个 TCP 套接字。connect_ex()
:尝试连接目标 IP 的指定端口,返回值0
表示端口开放。settimeout()
:设置连接超时时间为1
秒,避免因部分端口长时间未响应而导致程序卡住。
输出示例
正在扫描目标 IP 114.66.41.155 的端口...
端口 22 是开放的
端口 80 是开放的
端口 443 是开放的扫描完成,开放的端口:[22, 80, 443]
优化版:多线程扫描
为了加快扫描速度,可以使用多线程扫描。以下是使用 concurrent.futures
的多线程实现:
import socket
import time
from concurrent.futures import ThreadPoolExecutor# 设置目标 IP 地址
target_ip = "114.66.41.155"# 定义需要扫描的端口范围
start_port = 1
end_port = 65535 # 扫描所有可能的 TCP 端口# 创建一个列表来存储开放的端口
open_ports = []# 定义端口扫描函数
def scan_port(port):try:# 创建一个 socket 对象sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.settimeout(0.5) # 设置超时时间为 0.5 秒result = sock.connect_ex((target_ip, port))if result == 0:print(f"端口 {port} 是开放的")open_ports.append(port)sock.close()except Exception as e:print(f"扫描端口 {port} 时发生错误: {e}")# 使用线程池扫描端口
def scan_ports():with ThreadPoolExecutor(max_workers=100) as executor: # 设置最大线程数为 100# 提交任务到线程池futures = [executor.submit(scan_port, port) for port in range(start_port, end_port + 1)]# 等待所有任务完成for future in concurrent.futures.as_completed(futures):pass# 打印所有开放的端口print(f"\n扫描完成,开放的端口:{open_ports}")# 执行端口扫描
if __name__ == "__main__":print(f"正在扫描目标 IP {target_ip} 的端口...")start_time = time.time() # 记录开始时间scan_ports()end_time = time.time() # 记录结束时间print(f"扫描耗时: {end_time - start_time:.2f} 秒")
代码说明
ThreadPoolExecutor
:使用线程池管理多线程,避免手动创建和管理线程。max_workers=100
:设置最大线程数为 100,可以根据系统性能调整。concurrent.futures.as_completed()
:等待所有任务完成后继续执行。
输出示例
正在扫描目标 IP 114.66.41.155 的端口...
端口 22 是开放的
端口 80 是开放的
端口 443 是开放的扫描完成,开放的端口:[22, 80, 443]
扫描耗时: 120.56 秒
代码优化与性能提升
1. 调整超时时间
- 超时时间设置得太长会拖慢扫描速度,设置得太短可能导致误判。建议根据目标主机的网络状况调整,例如设置为
0.5
秒。
2. 分段扫描
- 如果目标主机响应较慢,可以先扫描常用端口(
1-1024
),再扫描其他端口,分段进行扫描。
3. 使用异步 I/O
- 如果需要进一步提高性能,可以使用
asyncio
实现异步端口扫描。
4. 防止被检测
- 长时间扫描可能触发目标主机的防火墙或安全策略。可以通过随机化扫描顺序或降低扫描频率来减少被检测的风险。
总结与扩展
本文介绍了如何使用 Python 实现快速识别目标主机的开放端口,提供了基础的单线程扫描和优化的多线程扫描两种实现方式。通过 concurrent.futures
,可以显著提高扫描效率,适合扫描大量端口(如 65535 个端口)。
扩展方向
- 使用
nmap
的 Python 接口:- 如果需要更强大的功能,可以使用
python-nmap
库,它基于nmap
工具,功能更强大。
- 如果需要更强大的功能,可以使用
- 可视化扫描结果:
- 可以将扫描结果保存到文件或生成图表,方便后续分析。
- 扫描多个目标主机:
- 可以扩展为扫描多个 IP 地址,进一步提高工具的通用性。
参考代码
以下是完整代码实现,可以直接运行:
import socket
import time
from concurrent.futures import ThreadPoolExecutor# 设置目标 IP 地址
target_ip = "114.66.41.155"# 定义需要扫描的端口范围
start_port = 1
end_port = 65535 # 扫描所有可能的 TCP 端口# 创建一个列表来存储开放的端口
open_ports = []# 定义端口扫描函数
def scan_port(port):try:# 创建一个 socket 对象sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.settimeout(0.5) # 设置超时时间为 0.5 秒result = sock.connect_ex((target_ip, port))if result == 0:print(f"端口 {port} 是开放的")open_ports.append(port)sock.close()except Exception as e:print(f"扫描端口 {port} 时发生错误: {e}")# 使用线程池扫描端口
def scan_ports():with ThreadPoolExecutor(max_workers=100) as executor: # 设置最大线程数为 100# 提交任务到线程池futures = [executor.submit(scan_port, port) for port in range(start_port, end_port + 1)]# 等待所有任务完成for future in concurrent.futures.as_completed(futures):pass# 打印所有开放的端口print(f"\n扫描完成,开放的端口:{open_ports}")# 执行端口扫描
if __name__ == "__main__":print(f"正在扫描目标 IP {target_ip} 的端口...")start_time = time.time() # 记录开始时间scan_ports()end_time = time.time() # 记录结束时间print(f"扫描耗时: {end_time - start_time:.2f} 秒")
总结
- 优点:代码简洁易懂,性能较高。
- 适用场景:适合快速识别目标主机的开放端口,适用于简单的网络监控或安全审计。
- 注意事项:请确保在合法合规的情况下使用端口扫描工具,未经授权扫描可能违反相关法律法规。
希望本文对你有所帮助!如果还有其他问题,欢迎继续交流。 😊