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