345 lines
12 KiB
Python
345 lines
12 KiB
Python
# 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)
|