LISHUZUOXUN_yangjiang/LSZXNetWork/network.py

312 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.

import ping3
from ping3.errors import PingError
import concurrent.futures
from AcrossPlatform.get_platform import *
from DeviceDefine.consensus import UNKNOWN, MANAGER, SLAVER
from LSZXNetWork.NetworkDriverWin32.wifi_ap import get_self_ip_address
from LSZXNetWork.encrypt import wifi_ap_name_generate, wifi_password_generate, SSID_HEAD
# 根据平台导入对应的包
if SYS_PLATFORM == WINDOWS:
from LSZXNetWork.NetworkDriverWin32 import wifi
from LSZXNetWork.NetworkDriverWin32 import wifi_ap
elif SYS_PLATFORM == LINUX:
from LSZXNetWork.NetworkDriverLinux import wifi
from LSZXNetWork.NetworkDriverLinux import wifi_ap
import socket
import threading
import time
import traceback
# 定义数据包长度
DATA_LENGTH = 5
DEFAULT_MASTER_ADDRESS = "192.168.137.1"
class Network:
NETWORK_SERVER_PORT = 13131
NETWORK_CLIENT_PORT = 13132
def __init__(self, master_mode=True, device_type=UNKNOWN):
super().__init__()
# 设备类型
self.device_type = device_type
self.ap = wifi_ap.WiFiAP()
self.wifi = wifi.WIFI()
self.ssid = wifi_ap_name_generate()
self.master_mode = master_mode
if master_mode:
self.start_ap()
self.master_ip = DEFAULT_MASTER_ADDRESS
self.ip = "0.0.0.0"
self.other_ip = {}
self.device_lookup = {}
self.connected_wifi_mes = None
self.last_time = time.time()
threading.Thread(target=self._threading_wifi_daemon, daemon=True).start()
threading.Thread(target=self._threading_ip_assignment, daemon=True).start()
threading.Thread(target=self._threading_ping, daemon=True).start()
threading.Thread(target=self._threading_ip_sense, daemon=True).start()
def get_ssid(self):
return self.ssid
def get_connected_wifi(self):
wifi_mes = {
"is_connected": self.wifi.wifi_connect_status(),
"wifi_name": self.wifi.get_connected_wifi_name()
}
return wifi_mes
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.master_mode = True
def stop_ap(self):
self.ap.stop()
self.master_mode = False
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)
def get_connected_wifi_name(self):
return self.wifi.get_connected_wifi_name()
def disconnect(self):
self.connected_wifi_mes = None
self.wifi.disconnect()
def get_master_ip(self):
return self.master_ip
def get_self_ip(self):
return self.ip
def get_other(self):
other_ip = list(
filter(
lambda ip: ip != self.ip,
self.other_ip.keys()
)
)
return other_ip
def get_manager(self):
manager_list = list(
filter(
lambda ip: self.device_lookup[ip] == MANAGER,
self.device_lookup
)
)
return manager_list
def get_slaver(self):
slaver_list = list(
filter(
lambda ip: self.device_lookup[ip] == SLAVER and ip != DEFAULT_MASTER_ADDRESS,
self.device_lookup
)
)
return slaver_list
# wifi守护进程当WiFi链接中断时重新链接
def _threading_wifi_daemon(self):
while True:
try:
if not self.master_mode and self.connected_wifi_mes:
ssid, password = self.connected_wifi_mes
if self.get_connected_wifi_name() != ssid:
self.wifi.connect_wifi(ssid=ssid, password=password)
except Exception as e:
print(f"wifi守护出错错误原因{e.args},\n{traceback.format_exc()}")
time.sleep(1)
time.sleep(3)
@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_assignment(self):
while True:
try:
# 获取当前设备中其他设备
ip_list = wifi_ap.get_machine_ip_address()
# 获取自身ip
self_ip = wifi_ap.get_self_ip_address()
# 从机IP
slaver_ip = ip_list.copy()
if not ip_list:
continue
self.ip = self_ip
# 标记已知的各类IP的标签
self.other_ip = {
ip: int(self.device_lookup.get(ip)).to_bytes(length=1, byteorder="big", signed=False)
if self.device_lookup.get(ip)
else int(UNKNOWN).to_bytes(length=1, byteorder="big", signed=False)
for ip in slaver_ip
}
# 对每一IP做类型广播
for ip in slaver_ip:
ip_bytes = b""
ip_mes = ip.split(".")
ip_bytes += b"".join([
int(seg).to_bytes(length=1, byteorder="big", signed=False)
for seg in ip_mes
])
# 增加该IP类型
device_type = self.device_lookup.get(ip)
if device_type:
ip_bytes += int(device_type).to_bytes(length=1, byteorder="big", signed=False)
else:
ip_bytes += int(UNKNOWN).to_bytes(length=1, byteorder="big", signed=False)
other_ips = ip_list.copy()
for ip_mes in other_ips:
ip_segment = b"".join([
int(seg).to_bytes(length=1, byteorder="big", signed=False)
for seg in ip_mes.split(".")
])
# 添加设备类型
device_type = self.device_lookup.get(ip_mes)
if device_type:
ip_segment += int(device_type).to_bytes(length=1, byteorder="big", signed=False)
else:
ip_segment += int(UNKNOWN).to_bytes(length=1, byteorder="big", signed=False)
ip_bytes += ip_segment
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.bind((self.ip, 0))
client.settimeout(1)
client.connect((ip, Network.NETWORK_SERVER_PORT))
client.send(ip_bytes)
device_type = client.recv(1)
client.close()
# 更新设备类型
self.device_lookup[ip] = int.from_bytes(device_type, signed=False, byteorder="big")
self.other_ip[ip] = int.from_bytes(device_type, signed=False, byteorder="big")
except ConnectionAbortedError or ConnectionRefusedError or ConnectionResetError:
continue
except socket.timeout:
continue
except ConnectionError:
continue
except OSError:
continue
except Exception as e:
print(f"WiFi分配出错错误原因{e.args},\n{traceback.format_exc()}")
time.sleep(1)
def _threading_ip_sense(self):
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.bind(("0.0.0.0", Network.NETWORK_SERVER_PORT))
tcp_server.listen(16)
tcp_server.settimeout(1)
while True:
# 被动模式
# 等待客户端连接
try:
conn, connected_addr = tcp_server.accept()
conn: socket.socket
conn.settimeout(1)
while True:
try:
data = conn.recv(1024)
if data:
conn.send(int(self.device_type).to_bytes(length=1, byteorder="big", signed=False))
ip_seg = [data[i: i + DATA_LENGTH] for i in range(0, len(data), DATA_LENGTH)]
self_ip = ".".join([
str(int(ip_mes))
for ip_mes in ip_seg[0][0: 4]
])
master_ip = ".".join([
str(int(ip_mes))
for ip_mes in ip_seg[-1][0: 4]
])
other_ips = [
".".join([
str(int(ip_mes))
for ip_mes in ip[0: 4]
])
for ip in ip_seg[1:-1]
]
others_device_type = [
ip[4]
for ip in ip_seg[1:-1]
]
new_other_ip = {
other_ips[i]: self.other_ip.get(other_ips[i])
if others_device_type[i] == UNKNOWN and other_ips[i] in self.other_ip.keys()
else int(others_device_type[i])
for i in range(len(other_ips))
}
self.other_ip.update(new_other_ip)
else:
break
except socket.timeout:
continue
except socket.timeout:
continue
except ConnectionResetError:
continue
except Exception as e:
# print(f"WiFi感知出错错误原因{e.args},\n{traceback.format_exc()}")
tcp_server.close()
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.bind(("0.0.0.0", Network.NETWORK_SERVER_PORT))
tcp_server.listen(16)
tcp_server.settimeout(1)