如何用Python的socket模块无连接枚举本地网络可用服务器?
用Python Socket模块无连接枚举本地网络服务器
要在本地WiFi网络中无连接枚举服务器,核心思路是利用UDP广播(无连接协议)或者ICMP探测,无需和目标建立完整TCP连接。以下是两种可行方案:
方案一:UDP广播探测(推荐)
UDP是无连接协议,客户端向本地网络的广播地址发送探测包,监听该广播端口的服务器收到后回复自身信息,客户端即可收集到服务器IP。
客户端实现代码
import socket import threading def listen_for_responses(): # 创建UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定到监听端口(和服务器监听端口一致) sock.bind(('', 5000)) print("等待服务器响应...") while True: data, addr = sock.recvfrom(1024) print(f"发现服务器: {addr[0]},消息: {data.decode('utf-8')}") # 启动监听线程 threading.Thread(target=listen_for_responses, daemon=True).start() # 发送广播探测包 broadcast_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) broadcast_sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # 本地网络广播地址(通常是网关地址最后一位改为255,比如192.168.1.255) broadcast_addr = ('192.168.1.255', 5000) broadcast_sock.sendto(b'Hello, servers?', broadcast_addr) # 保持程序运行 input("按回车退出...\n")
服务器端监听代码(需在目标服务器上运行)
import socket # 创建UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定到广播端口 sock.bind(('', 5000)) print("服务器监听广播中...") while True: data, addr = sock.recvfrom(1024) print(f"收到来自{addr[0]}的探测: {data.decode('utf-8')}") # 回复客户端,告知自身存在 sock.sendto(b'这里是服务器', addr)
方案二:ICMP Ping扫描(无连接探测存活主机)
通过发送ICMP Echo请求(Ping)来探测网络中存活的主机,无需建立TCP/UDP连接。注意:此方法需要管理员/root权限,因为要使用原始套接字。
实现代码
import socket import struct import time def icmp_ping(host): # 创建原始套接字,ICMP协议 try: sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) except PermissionError: print("需要管理员/root权限才能运行此扫描") return False # 构造ICMP包 icmp_type = 8 # Echo请求 icmp_code = 0 icmp_checksum = 0 icmp_id = 12345 icmp_seq = 1 # 先构造无校验和的包 header = struct.pack('!BBHHH', icmp_type, icmp_code, icmp_checksum, icmp_id, icmp_seq) data = b'Hello' # 计算校验和 icmp_checksum = calculate_checksum(header + data) header = struct.pack('!BBHHH', icmp_type, icmp_code, icmp_checksum, icmp_id, icmp_seq) packet = header + data # 发送包 sock.sendto(packet, (host, 0)) sock.settimeout(1) try: recv_packet, addr = sock.recvfrom(1024) # 提取ICMP头部 icmp_header = recv_packet[20:28] recv_type, recv_code, _, recv_id, recv_seq = struct.unpack('!BBHHH', icmp_header) if recv_type == 0 and recv_id == icmp_id: print(f"主机 {host} 存活") return True except socket.timeout: print(f"主机 {host} 无响应") return False finally: sock.close() def calculate_checksum(data): checksum = 0 data_len = len(data) if data_len % 2 != 0: data += b'\x00' data_len += 1 for i in range(0, data_len, 2): word = (data[i] << 8) + data[i+1] checksum += word checksum = (checksum >> 16) + (checksum & 0xffff) checksum = ~checksum & 0xffff return checksum # 扫描本地网段,比如192.168.1.1到192.168.1.254 for i in range(1, 255): host = f'192.168.1.{i}' icmp_ping(host)
注意事项
- UDP广播方案需要服务器配合监听广播端口,适合可控的服务器场景;ICMP扫描无需服务器配合,但需要权限,且部分主机可能禁用ICMP响应。
- 本地网络广播地址需要根据实际网段调整,可以通过
ipconfig(Windows)或ifconfig(Linux/macOS)查看网关地址,将最后一位改为255。 - 多线程/多进程可以加速ICMP扫描,避免逐个扫描耗时过长。
内容的提问来源于stack exchange,提问作者SeyitAli002
相关产品推荐
相关产品推荐

