当前位置:首页 > Python > 正文

Python检测端口是否开放教程 - 简单高效的端口扫描方法

Python检测端口是否开放教程

作者: 网络技术专家 | 发布日期: 2023年10月15日 | 阅读时间: 8分钟

内容大纲:

  • 端口检测的基本原理
  • Python socket模块介绍
  • 单端口检测实现
  • 多端口扫描实现
  • 完整端口扫描器代码
  • 应用场景与注意事项

为什么需要检测端口开放状态?

端口检测是网络管理和网络安全的基础操作之一,主要用途包括:

  • 检查服务器特定服务是否正常运行(如HTTP/80,HTTPS/443)
  • 网络安全评估和漏洞扫描
  • 网络故障排查
  • 监控网络服务可用性

端口检测基本原理

端口检测的基本原理是尝试与目标主机的特定端口建立TCP连接:

  1. 创建TCP socket对象
  2. 设置适当的超时时间
  3. 尝试连接目标主机的指定端口
  4. 根据连接结果判断端口状态:
    • 连接成功 → 端口开放
    • 连接被拒绝 → 端口关闭
    • 连接超时 → 端口可能被防火墙过滤

Python socket模块介绍

Python内置的socket模块提供了访问操作系统Socket接口的功能,是网络编程的核心模块。

主要方法:

  • socket() - 创建新的socket对象
  • connect() - 连接到远程地址
  • send() - 发送数据
  • recv() - 接收数据
  • close() - 关闭连接

单端口检测实现

以下是一个简单的Python函数,用于检测单个端口状态:

import socket

def check_port(host, port, timeout=2):
    """
    检测指定主机和端口是否开放
    :param host: 目标主机IP或域名
    :param port: 目标端口
    :param timeout: 超时时间(秒)
    :return: 布尔值,True表示端口开放
    """
    try:
        # 创建TCP socket
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        
        # 尝试连接
        result = sock.connect_ex((host, port))
        
        # 判断连接结果
        if result == 0:
            print(f"端口 {port} 是开放的")
            return True
        else:
            print(f"端口 {port} 是关闭的")
            return False
    except socket.error as err:
        print(f"检测端口 {port} 时出错: {err}")
        return False
    finally:
        # 确保关闭socket连接
        sock.close()

# 使用示例
check_port("www.example.com", 80)  # 检测HTTP端口
check_port("192.168.1.1", 22)      # 检测SSH端口
        

代码说明:

  • socket.AF_INET 表示使用IPv4地址
  • socket.SOCK_STREAM 表示使用TCP协议
  • connect_ex() 返回错误代码而不是抛出异常
  • 使用try-except-finally确保资源正确释放

多端口扫描实现

实际应用中,我们通常需要扫描多个端口。下面是增强版本:

import socket
import concurrent.futures

def scan_ports(host, ports, max_workers=100, timeout=1):
    """
    扫描目标主机的多个端口
    :param host: 目标主机
    :param ports: 端口列表
    :param max_workers: 最大并发线程数
    :param timeout: 每个连接的超时时间
    """
    open_ports = []
    
    print(f"开始扫描主机: {host}")
    print("-" * 50)
    
    # 使用线程池提高扫描效率
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        # 为每个端口创建检测任务
        future_to_port = {executor.submit(check_port, host, port, timeout): port for port in ports}
        
        # 处理完成的任务
        for future in concurrent.futures.as_completed(future_to_port):
            port = future_to_port[future]
            try:
                is_open = future.result()
                if is_open:
                    open_ports.append(port)
            except Exception as e:
                print(f"端口 {port} 扫描出错: {e}")
    
    print("\n扫描完成!")
    print("-" * 50)
    print(f"开放端口列表: {sorted(open_ports)}")
    return open_ports

# 扫描常用端口
common_ports = [21, 22, 23, 25, 53, 80, 110, 143, 443, 465, 587, 993, 995, 3306, 3389]
scan_ports("www.yourdomain.com", common_ports)
        

代码说明:

  • 使用线程池并发执行多个端口检测,显著提高效率
  • 限制最大并发数避免对目标主机造成过大压力
  • 收集并返回所有开放端口列表
  • 扫描常见服务端口(可自定义端口列表)

完整端口扫描器代码

结合上述功能,创建一个功能完整的端口扫描工具:

import socket
import concurrent.futures
import time
import argparse

# 常用端口列表(可根据需要扩展)
WELL_KNOWN_PORTS = {
    20: "FTP-DATA", 21: "FTP", 22: "SSH", 23: "Telnet",
    25: "SMTP", 53: "DNS", 67: "DHCP", 68: "DHCP",
    80: "HTTP", 110: "POP3", 119: "NNTP", 123: "NTP",
    143: "IMAP", 161: "SNMP", 194: "IRC", 443: "HTTPS",
    465: "SMTPS", 587: "SMTP", 993: "IMAPS", 995: "POP3S",
    1433: "MSSQL", 1521: "Oracle", 3306: "MySQL", 3389: "RDP",
    5432: "PostgreSQL", 5900: "VNC", 6379: "Redis", 8080: "HTTP-Proxy"
}

def check_port(host, port, timeout=1.5):
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(timeout)
            result = s.connect_ex((host, port))
            return result == 0
    except:
        return False

def port_scan(host, ports, max_threads=200, timeout=1.5):
    open_ports = {}
    
    print(f"🚀 开始扫描主机: {host}")
    print(f"📋 扫描端口数量: {len(ports)}")
    print(f"⚡ 线程数: {max_threads}")
    print("-" * 60)
    
    start_time = time.time()
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_threads) as executor:
        futures = {executor.submit(check_port, host, port, timeout): port for port in ports}
        
        for i, future in enumerate(concurrent.futures.as_completed(futures)):
            port = futures[future]
            try:
                if future.result():
                    service = WELL_KNOWN_PORTS.get(port, "Unknown")
                    print(f"✅ 端口 {port}/TCP 开放 ({service})")
                    open_ports[port] = service
                else:
                    print(f"❌ 端口 {port}/TCP 关闭", end='\r')
            except Exception as e:
                print(f"⚠️ 端口 {port} 扫描出错: {e}")
    
    duration = time.time() - start_time
    print("\n" + "-" * 60)
    print(f"扫描完成! 耗时: {duration:.2f}秒")
    print(f"开放端口数量: {len(open_ports)}")
    
    if open_ports:
        print("\n开放端口列表:")
        print("-" * 30)
        for port, service in open_ports.items():
            print(f"端口 {port}/TCP: {service}")
    
    return open_ports

if __name__ == "__main__":
    # 设置命令行参数解析
    parser = argparse.ArgumentParser(description="Python端口扫描器")
    parser.add_argument("host", help="目标主机名或IP地址")
    parser.add_argument("-p", "--ports", nargs="?", default="1-1024", 
                        help="端口范围 (默认: 1-1024), 或指定端口列表,如:80,443,8080")
    parser.add_argument("-t", "--threads", type=int, default=200, 
                        help="最大线程数 (默认: 200)")
    parser.add_argument("-T", "--timeout", type=float, default=1.5, 
                        help="连接超时时间(秒) (默认: 1.5)")
    
    args = parser.parse_args()
    
    # 处理端口范围
    ports = []
    if ',' in args.ports:
        # 逗号分隔的端口列表
        ports = [int(p.strip()) for p in args.ports.split(',')]
    elif '-' in args.ports:
        # 端口范围
        start, end = map(int, args.ports.split('-'))
        ports = list(range(start, end + 1))
    else:
        # 单个端口
        ports = [int(args.ports)]
    
    # 执行扫描
    port_scan(args.host, ports, args.threads, args.timeout)
        

功能特点:

  • 支持命令行参数:目标主机、端口范围、线程数、超时时间
  • 智能端口范围解析(支持单个端口、端口列表和端口范围)
  • 显示端口对应的常见服务
  • 实时扫描进度显示
  • 详细扫描结果报告
  • 多线程并发提高效率

使用示例:

将代码保存为port_scanner.py后:

# 扫描常用端口
python port_scanner.py www.example.com

# 扫描指定端口范围
python port_scanner.py 192.168.1.1 -p 20-100

# 扫描特定端口
python port_scanner.py example.com -p 80,443,8080

# 使用500线程扫描
python port_scanner.py target.com -p 1-65535 -t 500
        

应用场景与注意事项

典型应用场景:

  • 服务器管理员检查服务端口状态
  • 网络安全人员评估系统安全性
  • 开发人员调试网络应用程序
  • 监控系统定期检查服务可用性

重要注意事项:

  • ⚠️ 仅扫描你有权限测试的主机
  • ⚠️ 未经授权扫描他人网络可能违法
  • ⚠️ 避免对目标主机发起过多并发连接(建议不超过500线程)
  • ✅ 适当调整超时时间以平衡准确性和效率
  • ✅ 使用已知端口字典可以更好地识别服务
  • ✅ 考虑添加日志记录功能以便长期监控

可能的扩展方向:

  • 添加UDP端口扫描支持
  • 实现服务指纹识别(banner grabbing)
  • 添加图形用户界面(GUI)
  • 集成到监控系统中定期执行
  • 添加电子邮件/短信通知功能

总结

Python的socket模块为端口检测提供了强大而灵活的基础功能。通过本教程,你学会了:

  1. 使用socket模块检测单个端口状态
  2. 利用多线程实现高效端口扫描
  3. 构建功能完整的命令行端口扫描工具
  4. 理解端口扫描的应用场景和注意事项

这些技能对于网络管理、安全评估和系统监控都非常有价值。请始终遵守法律法规,合理使用这些技术。

发表评论