# coding: gb2312 import concurrent.futures import ping3 from ping3.errors import PingError from AcrossPlatform.get_platform import * from DeviceDefine.consensus import UNKNOWN, MANAGER, SLAVER from LSZXNetWork.consensus import * from LSZXNetWork.encrypt import wifi_ap_name_generate, wifi_password_generate, SSID_HEAD from LSZXNetWork.transmission import Client, Server from LogRecord.log_recorder import GLOBAL_LOG # 根据平台导入对应的包 if SYS_PLATFORM == WINDOWS: from LSZXNetWork.NetworkDriverWin32 import wifi from LSZXNetWork.NetworkDriverWin32 import wifi_ap from LSZXNetWork.NetworkDriverWin32.wifi_ap import ( get_self_ip_address, kill_port, get_machine_ip_address, get_wifi_ap_status ) elif SYS_PLATFORM == LINUX: from LSZXNetWork.NetworkDriverLinux import wifi from LSZXNetWork.NetworkDriverLinux import wifi_ap from LSZXNetWork.NetworkDriverLinux.wifi_ap import ( kill_port, get_machine_ip_address, get_wifi_ap_status ) from LSZXNetWork.NetworkDriverLinux.wifi import get_self_ip_address import threading import time import traceback # 定义数据包长度 DATA_LENGTH = 5 # 默认主机网络 DEFAULT_MASTER_ADDRESS = "192.168.137.1" # 信息网络网段(展示网络的ip分配应不超过192.168.138.32) DEFAULT_DISPLAY_SEGMENT = "192.168.138." # 主机网络网段 DEFAULT_MASTER_SEGMENT = "192.168.137." DEFAULT_SELF_IP = '0.0.0.0' class Network: NETWORK_SERVER_PORT = 13131 NETWORK_CLIENT_PORT = 13132 def __init__(self, master_mode=True, device_type=UNKNOWN): """ 主机网络下,只有一个主机,若干从机。从机向主机报告自身ip,主机记录ip并将其他从机ip发送至该从机。 信息网络下,没有主机,全部设备都是从机,机器网络通过arp命令直接获取,同时通过周期ping发现其他未寻找到的设备。 """ super().__init__() kill_port(Network.NETWORK_SERVER_PORT) kill_port(Network.NETWORK_CLIENT_PORT) # 设备类型 self.device_type = device_type # 设备热点 self.ap = wifi_ap.WiFiAP() # 设备WiFi self.wifi = wifi.WIFI() # AP名称 self.ssid = wifi_ap_name_generate() self.master_mode = master_mode self.ap_is_start = False # 如果网络为主机网络,启动AP if master_mode: GLOBAL_LOG.write("启动设备AP!") self.start_ap() self.master_ip = DEFAULT_MASTER_ADDRESS self.ip = DEFAULT_SELF_IP self.other_ip = {} self.device_lookup = {} self.connected_wifi_mes = None self.last_time = time.time() self.client = Client(ip=DEFAULT_SELF_IP) self.server = Server(ip=DEFAULT_SELF_IP, port=Network.NETWORK_SERVER_PORT) self.alive_timeout = 10 threading.Thread(target=self._threading_wifi_daemon, daemon=True).start() threading.Thread(target=self._threading_ap_daemon, daemon=True).start() threading.Thread(target=self._threading_ping, daemon=True).start() threading.Thread(target=self._threading_ip_receiver, daemon=True).start() threading.Thread(target=self._threading_ip_distribution, daemon=True).start() threading.Thread(target=self._threading_ip_report, daemon=True).start() def get_ssid(self): return self.ssid # 获得当前链接的WiFi def get_connected_wifi(self): wifi_name = self.wifi.get_connected_wifi_name() return wifi_name # 获得可用的WiFi def get_available_wifi(self): available_wifi = self.wifi.scan_wifi() available_wifi_name = [str(_wifi) for _wifi in available_wifi] available_wifi_name = list(filter(lambda s: SSID_HEAD in s, available_wifi_name)) available_wifi_name = list(set(available_wifi_name)) return available_wifi_name # 启动热点 def start_ap(self): password = wifi_password_generate(self.ssid) self.ap.set_ssid(self.ssid) self.ap.set_password(password) self.ap.start() self.ap_is_start = True # 关闭热点 def stop_ap(self): self.ap.stop() self.ap_is_start = False # 连接到WiFi def connect2wifi(self, ssid): self.stop_ap() self.wifi.wifi_device_initial() password = wifi_password_generate(ssid) self.connected_wifi_mes = (ssid, password) self.other_ip.clear() self.device_lookup.clear() return self.wifi.connect_wifi(ssid=ssid, password=password) # 获得当前链接的WiFi名称 def get_connected_wifi_name(self): return self.wifi.get_connected_wifi_name() # 断开当前的WiFi链接 def disconnect(self): self.connected_wifi_mes = None self.wifi.disconnect() self.start_ap() # 获得主机ip def get_master_ip(self): return self.master_ip # 获得自身ip def get_self_ip(self): return self.ip # 获得其他ip def get_other(self): this_time = time.time() other_ip = list( filter( lambda ip: ip != self.ip and this_time - self.device_lookup[ip][TIME] < self.alive_timeout, self.device_lookup.keys() ) ) return other_ip # 获得Manager的ip def get_manager(self): this_time = time.time() manager_list = list( filter( lambda ip: self.device_lookup[ip][DEVICE_TYPE] == MANAGER and this_time - self.device_lookup[ip][TIME] < self.alive_timeout, self.device_lookup.keys() ) ) return manager_list # 获得从机IP def get_slaver(self): this_time = time.time() slaver_list = list( filter( lambda ip: self.device_lookup[ip][DEVICE_TYPE] == SLAVER and ip != DEFAULT_MASTER_ADDRESS and this_time - self.device_lookup[ip][TIME] < self.alive_timeout, self.device_lookup.keys() ) ) return slaver_list # wifi守护进程(当WiFi链接中断时,重新链接) def _threading_wifi_daemon(self): while True: try: # 如果当前不是AP模式,并且当前有链接的WiFi,则进入WiFi守护模式,检查WiFi是否正确链接 if not self.ap_is_start: if not self.connected_wifi_mes: time.sleep(1) continue ssid, password = self.connected_wifi_mes if self.get_connected_wifi_name() != ssid: # 如果WiFi没有正常链接,则重新链接到指定的WiFi self.wifi.connect_wifi(ssid=ssid, password=password) except Exception as e: GLOBAL_LOG.write(f"wifi守护出错,错误原因:{e.args},\n{traceback.format_exc()}") time.sleep(1) time.sleep(2) # ap守护进程(当ap链接中断时,重新启动) def _threading_ap_daemon(self): while True: try: # 如果当前是AP模式,则进入ap守护模式 if self.ap_is_start: if not get_wifi_ap_status(): self.ap.reboot() except Exception as e: GLOBAL_LOG.write(f"ap守护出错,错误原因:{e.args},\n{traceback.format_exc()}") time.sleep(1) @staticmethod def ping_task(ip): try: ping3.ping(ip, timeout=30, unit="ms", size=1) except PingError: return # 尝试ping网段下所有网络,保证设备正常识别 def network_discover(self): ping_pool_num = 16 self_ip = get_self_ip_address() base_segments = self_ip.split(".")[0:3] # 创建一个线程池,最大线程数为ping_pool_num with concurrent.futures.ThreadPoolExecutor(max_workers=ping_pool_num) as executor: # 提交任务到线程池 for i in range(2, 255): ip = ".".join(base_segments + [str(i)]) executor.submit(self.ping_task, ip) # 网络设备识别 def _threading_ping(self): while True: # 尝试ping通主机网络下其他设备。 self.network_discover() # 每隔30秒打印网络信息。 if time.time() - self.last_time > 30: self.last_time = time.time() print( "@网络成员打印:", "SELF", self.get_self_ip(), "MASTER", self.get_master_ip(), "SLAVER", self.get_slaver(), "MANAGER", self.get_manager(), "OTHERS", self.get_other(), ) # print(self.device_lookup) time.sleep(1) # 网络地址获取器 def _threading_ip_receiver(self): while True: try: data = self.server.get_data() mes_command = data[MES_COMMAND] reported_time = time.time() if mes_command == UPDATE: for ip, device_type in data[DATA].items(): self.device_lookup[ip] = { DEVICE_TYPE: device_type, TIME: reported_time } elif mes_command == DEL: self.device_lookup.clear() # print(self.device_lookup) except Exception as e: print(f"WiFi网络地址获取,错误原因:{e.args},\n{traceback.format_exc()}") GLOBAL_LOG.write(f"WiFi网络地址获取,错误原因:{e.args},\n{traceback.format_exc()}") # 如果设备为主机模式,则定时向从机设备发送其他设备ip def _threading_ip_distribution(self): while True: try: # 如果没有发射ap if not self.ap_is_start: time.sleep(1) continue # 如果发射ap # 更新设备列表 this_time = time.time() # 将自身加入到列表中 self.ip = DEFAULT_MASTER_ADDRESS self.device_lookup[self.ip] = { DEVICE_TYPE: self.device_type, TIME: this_time } alive_device_info = {} for ip, mes in self.device_lookup.items(): last_report_time = mes[TIME] if this_time - last_report_time < self.alive_timeout: alive_device_info[ip] = mes[DEVICE_TYPE] report_pkg = { MES_COMMAND: UPDATE, DATA: alive_device_info } # 向所有链接的设备发送设备对照表 lookup_table = self.device_lookup.copy() address_list = [(ip, Network.NETWORK_SERVER_PORT) for ip in lookup_table.keys()] pkg_list = [report_pkg for _ in lookup_table.keys()] self.client.distributed_send(address_list, pkg_list) # 休息一会 time.sleep(1) except Exception as e: GLOBAL_LOG.write(f"分发发生错误:{e.args}\n{traceback.format_exc()}") continue # 定时汇报自身ip def _threading_ip_report(self): while True: # 识别为主机 if self.ap_is_start: time.sleep(1) continue self.ip = get_self_ip_address() if self.ip == DEFAULT_SELF_IP: time.sleep(1) continue report_pkg = { MES_COMMAND: UPDATE, DATA: { self.ip: self.device_type } } # 识别为主机网络,并且本身没有开启热点,即不是主机:向主机发送自身IP,获得其他设备地址。 if DEFAULT_MASTER_SEGMENT in self.ip: self.master_ip = DEFAULT_MASTER_ADDRESS self.client.connect2(self.master_ip, Network.NETWORK_SERVER_PORT) self.client.send(report_pkg) # 识别为其他网络,如信息网络 else: # 获取其他设备ip all_ip = get_machine_ip_address() if not all_ip: continue self.ip = all_ip[0] # 向其他设备发送ip信息 address_list = [(ip, Network.NETWORK_SERVER_PORT) for ip in all_ip] pkg_list = [report_pkg for _ in all_ip] self.client.distributed_send(address_list, pkg_list) # 休息一会 time.sleep(1)