socket.connect_ex()可直接判断端口是否开放:返回0表示开放,ConnectionRefusedError表示关闭,TimeoutError可能被防火墙拦截;纯socket方案零依赖、跨平台、逻辑透明,局域网扫描设0.5秒超时即可兼顾速度与准确率。

直接用 socket 就能做,不需要额外装库;但别用多线程暴力扫全端口,容易被防火墙拦截或触发告警。
为什么不用 scapy 或 nmap Python 绑定?
多数局域网扫描只需判断“端口是否开放”,socket.connect() 的返回结果足够可靠。用 scapy 需要 root 权限,且在 Windows 上支持差;python-nmap 依赖系统级 nmap 安装,跨环境部署麻烦。纯 socket 方案零依赖、跨平台、逻辑透明。
- 局域网内延迟低,
socket连接超时设为0.5秒足够快又不误判 -
ConnectionRefusedError表示端口关闭,TimeoutError可能是防火墙丢包,需区分处理 - 避免并发数过高:局域网常见设备(如打印机、IoT)连接队列浅,10–20 路并发较稳妥
怎么写一个可指定 IP 段和端口范围的扫描函数?
核心是把 ipaddress.ip_network() 和 range() 结合,生成目标列表,再对每个 (host, port) 尝试建立 TCP 连接:
import socket
import ipaddress
from concurrent.futures import ThreadPoolExecutor
<p>def scan_port(host, port, timeout=0.5):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex((host, port))
sock.close()
return port, result == 0 # True 表示开放
except Exception:
return port, False</p><p>def scan_network(network_str, ports=[22, 80, 443, 8080], max_workers=15):
hosts = list(ipaddress.ip_network(network_str).hosts())
results = {}
for host in hosts:
host_str = str(host)
results[host_str] = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [executor.submit(scan_port, host_str, p) for p in ports]
for f in futures:
port, is_open = f.result()
if is_open:
results[host_str].append(port)
return results
-
network_str示例:"192.168.1.0/24",注意不能传"192.168.1.*"这类通配符 -
connect_ex()返回 0 表示成功,比connect()+ 异常捕获更简洁 - 不要在循环里反复创建
ThreadPoolExecutor,否则开销大;上面示例中每台主机独立建池,是为避免单个主机失败影响全局
扫描结果怎么看?哪些端口值得重点关注?
输出是字典:{"192.168.1.25": [22, 80], "192.168.1.30": [443]}。但光有开放端口还不够,得结合服务特征初步判断风险:
立即学习“Python免费学习笔记(深入)”;
-
22:SSH 服务,若未改默认端口且允许密码登录,易被爆破 -
23:Telnet,明文传输,局域网内也应禁用 -
139/445:SMB,Windows 共享,永恒之蓝类漏洞高发区 -
3389:RDP,外网暴露极危险,局域网内也建议限制访问源 -
5000、8000、8080:常见开发/管理后台,默认口令多,扫描后建议手动验证
注意:有些设备(如部分摄像头、路由器)会开放 80 但返回 401 或重定向到登录页,这类仍算“有效服务”,不能仅靠端口判断是否可利用。
真正难的不是扫出端口,而是确认开放端口背后跑的是什么版本、有没有已知 CVE、是否配置了弱口令——那已经超出简易工具范畴了。先确保你能稳定拿到真实开放状态,再考虑往上叠加 Banner 获取或协议识别。


















