本文将通过关键知识点,深入讲解端口扫描器的开发过程,有完整代码。
# connect_ex()返回值含义:
# 0 -> 端口开放(完成三次握手)
# 其他错误码 -> 端口关闭/过滤
socket.create_connection((target, port), timeout=1)
扫描类型 | 原理 | 特点 |
---|---|---|
TCP全连接 | 完整三次握手 | 准确但易被日志记录 |
SYN半开 | 仅发送SYN包 | 隐蔽性强需要root权限 |
UDP扫描 | 发送UDP数据包 | 不可靠但必要服务检测 |
class PortScanner:
def __init__(self, master):
# 使用Grid布局管理器
self.master = master
master.geometry("600x400") # 初始窗口尺寸
master.resizable(False, False) # 禁止调整大小
# 使用ttk主题组件提升视觉效果
self.style = ttk.Style()
self.style.configure('Treeview', rowheight=25) # 调整行高
def validate_input(self):
target = self.ip_entry.get()
# 域名解析验证
try:
# 同时支持IPv4和域名输入
socket.gethostbyname(target)
except socket.gaierror:
messagebox.showerror("错误", "无效的IP地址或域名")
return False
# 端口范围校验
try:
start = int(self.start_port.get())
end = int(self.end_port.get())
if not (1 <= start <= end <= 65535):
raise ValueError
except:
messagebox.showerror("错误", "端口范围应为1-65535的整数")
return False
return True
# 动态线程数计算公式(根据端口范围自动调整)
port_range = end_port - start_port + 1
thread_count = min(100, max(20, port_range // 10)) # 控制在20-100之间
# 使用ThreadPoolExecutor优化线程管理
with ThreadPoolExecutor(max_workers=thread_count) as executor:
futures = [executor.submit(self.port_scan, port) for port in range(start_port, end_port+1)]
# 添加进度条显示
self.progress = ttk.Progressbar(master, orient=HORIZONTAL,
length=200, mode='determinate')
self.progress.grid(row=4, columnspan=3)
# 队列状态更新函数
def update_progress():
while not port_queue.empty():
current = port_range - port_queue.qsize()
self.progress['value'] = (current/port_range)*100
time.sleep(0.1)
# 启动独立线程更新进度
threading.Thread(target=update_progress, daemon=True).start()
def detect_service(self, port):
# 常见端口服务映射
service_map = {
21: 'FTP',
22: 'SSH',
80: 'HTTP',
443: 'HTTPS',
3306: 'MySQL'
}
# 尝试获取Banner信息
try:
with socket.socket() as s:
s.settimeout(1)
s.connect((target, port))
banner = s.recv(1024).decode().strip()
return f"{service_map.get(port, '未知')} ({banner})"
except:
return service_map.get(port, '未知服务')
def export_results(self):
filename = filedialog.asksaveasfilename(
defaultextension=".csv",
filetypes=[("CSV文件", "*.csv"), ("文本文件", "*.txt")]
)
if filename:
with open(filename, 'w') as f:
f.write("端口,状态,服务,响应时间\n")
for item in self.result_tree.get_children():
values = self.result_tree.item(item)['values']
f.write(','.join(map(str, values)) + '\n')
# 随机扫描顺序
ports = list(range(start_port, end_port+1))
random.shuffle(ports) # 打乱扫描顺序
# 请求间隔随机化
time.sleep(random.uniform(0.1, 0.5)) # 降低检测概率
# 使用代理服务器
proxy = ("127.0.0.1", 1080)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_PROXY, proxy)
# 修改TcpAckFrequency注册表(Windows)
# 需要管理员权限运行
if platform.system() == 'Windows':
subprocess.run(
'reg add HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters '
'/v TcpAckFrequency /t REG_DWORD /d 1 /f',
shell=True
)