193 lines
7.1 KiB
Python
193 lines
7.1 KiB
Python
import socket
|
|
from threading import Thread, Event
|
|
from typing import Optional
|
|
from time import sleep, time
|
|
from queue import Queue
|
|
import re
|
|
|
|
|
|
class Server(object):
|
|
def __init__(self):
|
|
self._s = None
|
|
self._listen_th, self._receive_th = None, None
|
|
self.ip, self.port = None, None
|
|
self.client_ip, self.client_port, self.client_s = None, None, None
|
|
self._last_heartbeat = None
|
|
self._closing_callback = None
|
|
self._closing_signal = None
|
|
self._connected_callback = None
|
|
self._connected_signal = None
|
|
self._disconnected_callback = None
|
|
self._disconnected_signal = None
|
|
self._send_callback = None
|
|
self._send_signal = None
|
|
self._receive_callback = None
|
|
self._receive_signal = None
|
|
|
|
self._receive_queue = Queue()
|
|
self._timeout = 10.0
|
|
self._connection_status, self._need_recv_exit, self._need_listen_exit = Event(), Event(), Event()
|
|
|
|
def set_ip_port(self, ip: Optional[str] = None, port: Optional[int] = None):
|
|
if ip is not None:
|
|
self.ip = ip
|
|
if port is not None:
|
|
self.port = port
|
|
|
|
def set_heartbeat_timeout(self, timeout: float):
|
|
self._timeout = timeout
|
|
|
|
def set_closing_callback(self, callback):
|
|
self._closing_callback = callback
|
|
|
|
def set_closing_signal(self, signal):
|
|
self._closing_signal = signal
|
|
|
|
def set_connected_callback(self, callback):
|
|
self._connected_callback = callback
|
|
|
|
def set_connected_signal(self, signal):
|
|
self._connected_signal = signal
|
|
|
|
def set_disconnected_callback(self, callback):
|
|
self._disconnected_callback = callback
|
|
|
|
def set_disconnected_signal(self, signal):
|
|
self._disconnected_signal = signal
|
|
|
|
def set_send_callback(self, callback):
|
|
self._send_callback = callback
|
|
|
|
def set_send_signal(self, signal):
|
|
self._send_signal = signal
|
|
|
|
def set_receive_callback(self, callback):
|
|
self._receive_callback = callback
|
|
|
|
def set_receive_signal(self, signal):
|
|
self._receive_signal = signal
|
|
|
|
def _listen_thread(self, ip: str, port: int):
|
|
while not self._need_listen_exit.isSet():
|
|
if self._connection_status.isSet():
|
|
sleep(2)
|
|
continue
|
|
try:
|
|
self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self._s.bind((ip, port))
|
|
self._s.listen(1)
|
|
# print("connecting...")
|
|
self.client_s, (self.client_ip, self.client_port) = self._s.accept()
|
|
# print("connected")
|
|
self._connection_status.set()
|
|
self._need_recv_exit.clear()
|
|
self._receive_th = Thread(target=self._receive_thread)
|
|
self._receive_th.start()
|
|
if self._connected_callback is not None:
|
|
self._connected_callback()
|
|
if self._connected_signal is not None:
|
|
self._connected_signal.emit()
|
|
# print("receiving...")
|
|
except BaseException as e:
|
|
pass
|
|
self._close()
|
|
|
|
def _close(self) -> None:
|
|
try:
|
|
self.client_s.shutdown(socket.SHUT_RDWR)
|
|
self.client_s.close()
|
|
except BaseException as e:
|
|
pass
|
|
self.client_s, self.client_ip, self.client_port = None, None, None
|
|
self._last_heartbeat = None
|
|
self._connection_status.clear()
|
|
if self._disconnected_callback is not None:
|
|
self._disconnected_callback()
|
|
if self._disconnected_signal is not None:
|
|
self._disconnected_signal.emit()
|
|
self._need_recv_exit.set()
|
|
|
|
def close(self) -> None:
|
|
try:
|
|
self._s.close()
|
|
except BaseException as e:
|
|
pass
|
|
if self._closing_callback is not None:
|
|
self._closing_callback()
|
|
if self._closing_signal is not None:
|
|
self._closing_signal.emit()
|
|
self._close()
|
|
self._need_recv_exit.set()
|
|
self._need_listen_exit.set()
|
|
|
|
def is_connected(self) -> bool:
|
|
return self._connection_status.isSet()
|
|
|
|
def start_listen_thread(self, ip: Optional[str] = None, port: Optional[int] = None):
|
|
if ip is not None and port is not None:
|
|
self.ip, self.port = ip, port
|
|
self._listen_th = Thread(target=self._listen_thread, args=(self.ip, self.port))
|
|
self._listen_th.start()
|
|
|
|
def _receive_thread(self):
|
|
while not self._need_recv_exit.isSet():
|
|
data = None
|
|
if not self._connection_status.isSet():
|
|
sleep(2)
|
|
continue
|
|
try:
|
|
self.client_s.settimeout(2)
|
|
data = self.client_s.recv(1024)
|
|
except BaseException as e:
|
|
pass
|
|
if self._last_heartbeat is None:
|
|
self._last_heartbeat = time()
|
|
if time() - self._last_heartbeat > self._timeout:
|
|
# print(time() - self._last_heartbeat)
|
|
# print("timeout")
|
|
self._close()
|
|
|
|
if data is not None and len(data) != 0:
|
|
if self._receive_callback is not None:
|
|
self._receive_callback()
|
|
if self._receive_signal is not None:
|
|
self._receive_signal.emit(data)
|
|
# if data != b"\xaa\x00\x00\x00\x03hb\xff\xff\xff\xbb":
|
|
# self._receive_queue.put(data)
|
|
# else:
|
|
# pass
|
|
self._last_heartbeat = time()
|
|
|
|
def send_datagram(self, datagram: bytes):
|
|
try:
|
|
self.client_s.settimeout(2)
|
|
self.client_s.sendall(datagram)
|
|
if self._send_callback is not None:
|
|
self._send_callback(datagram)
|
|
if self._send_signal is not None:
|
|
self._send_signal.emit(datagram)
|
|
except BaseException as e:
|
|
# print(e)
|
|
self._close()
|
|
|
|
@classmethod
|
|
def get_server_ip_list(cls) -> list:
|
|
addrs = socket.getaddrinfo(socket.gethostname(), None)
|
|
addrs = [i[4][0] for i in addrs]
|
|
ip4_list = [i for i in addrs if
|
|
re.match(r"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
|
|
i) is not None]
|
|
ip6_list = [i for i in addrs if
|
|
re.match(
|
|
r"^([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,7}:$|^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$|^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$|^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$|^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$|^:((:[0-9a-fA-F]{1,4}){1,7}|:)$",
|
|
i) is not None]
|
|
ip4_list_192 = [i for i in ip4_list if re.match(r"^192\.168\.\S*$", i) is not None]
|
|
|
|
return ip4_list_192 + list(set(ip4_list) - set(ip4_list_192)) + ip6_list
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# s = Server()
|
|
# s.start_listen_thread("192.168.2.125", 13452)
|
|
Server.get_server_ip_list()
|