LISHUZUOXUN_yangjiang/LSZXNetWork/lszx_network.py

345 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)