685 lines
23 KiB
Python
685 lines
23 KiB
Python
"""
|
||
连接管理器模块
|
||
负责管理网络连接和客户端状态
|
||
"""
|
||
|
||
import time
|
||
from typing import Dict, Any, List, Optional
|
||
import threading
|
||
import socket
|
||
|
||
class ConnectionManager:
|
||
"""
|
||
连接管理器
|
||
负责管理网络连接和客户端状态
|
||
"""
|
||
|
||
def __init__(self, plugin):
|
||
"""
|
||
初始化连接管理器
|
||
|
||
Args:
|
||
plugin: 网络同步插件实例
|
||
"""
|
||
self.plugin = plugin
|
||
self.enabled = False
|
||
self.initialized = False
|
||
|
||
# 连接配置
|
||
self.connection_config = {
|
||
'max_connections': 32,
|
||
'connection_timeout': 30.0,
|
||
'reconnect_attempts': 3,
|
||
'reconnect_interval': 5.0,
|
||
'heartbeat_interval': 5.0,
|
||
'enable_auto_reconnect': True,
|
||
'enable_connection_limits': True,
|
||
'max_connections_per_ip': 5
|
||
}
|
||
|
||
# 客户端管理
|
||
self.clients = {} # 已连接的客户端
|
||
self.pending_connections = {} # 待处理的连接
|
||
self.banned_ips = set() # 被禁止的IP地址
|
||
|
||
# 服务器状态
|
||
self.server_state = {
|
||
'is_running': False,
|
||
'port': 7777,
|
||
'clients_connected': 0,
|
||
'peak_connections': 0,
|
||
'bytes_sent': 0,
|
||
'bytes_received': 0
|
||
}
|
||
|
||
# 客户端状态
|
||
self.client_state = {
|
||
'is_connected': False,
|
||
'server_address': '',
|
||
'server_port': 7777,
|
||
'connection_time': 0.0,
|
||
'last_heartbeat': 0.0,
|
||
'reconnect_attempts': 0
|
||
}
|
||
|
||
# 连接统计
|
||
self.connection_stats = {
|
||
'connections_accepted': 0,
|
||
'connections_rejected': 0,
|
||
'connections_lost': 0,
|
||
'connections_timed_out': 0,
|
||
'reconnections': 0,
|
||
'banned_connections': 0
|
||
}
|
||
|
||
# 线程管理
|
||
self.connection_thread = None
|
||
self.heartbeat_thread = None
|
||
self.reconnect_thread = None
|
||
self.running = False
|
||
|
||
# 回调函数
|
||
self.connection_callbacks = {
|
||
'client_connected': [],
|
||
'client_disconnected': [],
|
||
'connection_timeout': [],
|
||
'reconnect_attempt': [],
|
||
'connection_banned': []
|
||
}
|
||
|
||
# 时间戳记录
|
||
self.last_connection_check = 0.0
|
||
self.last_heartbeat_check = 0.0
|
||
self.last_reconnect_attempt = 0.0
|
||
|
||
print("✓ 连接管理器已创建")
|
||
|
||
def initialize(self) -> bool:
|
||
"""
|
||
初始化连接管理器
|
||
|
||
Returns:
|
||
是否初始化成功
|
||
"""
|
||
try:
|
||
self.initialized = True
|
||
print("✓ 连接管理器初始化完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接管理器初始化失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def enable(self) -> bool:
|
||
"""
|
||
启用连接管理器
|
||
|
||
Returns:
|
||
是否启用成功
|
||
"""
|
||
try:
|
||
if not self.initialized:
|
||
print("✗ 连接管理器未初始化")
|
||
return False
|
||
|
||
self.enabled = True
|
||
self.running = True
|
||
|
||
print("✓ 连接管理器已启用")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接管理器启用失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def disable(self):
|
||
"""禁用连接管理器"""
|
||
try:
|
||
self.enabled = False
|
||
self.running = False
|
||
|
||
# 断开所有连接
|
||
self._disconnect_all_clients()
|
||
self._disconnect_from_server()
|
||
|
||
print("✓ 连接管理器已禁用")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接管理器禁用失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def finalize(self):
|
||
"""清理连接管理器资源"""
|
||
try:
|
||
self.disable()
|
||
self.clients.clear()
|
||
self.pending_connections.clear()
|
||
self.banned_ips.clear()
|
||
self.connection_callbacks.clear()
|
||
self.initialized = False
|
||
print("✓ 连接管理器资源已清理")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接管理器资源清理失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def update(self, dt: float):
|
||
"""
|
||
更新连接管理器状态
|
||
|
||
Args:
|
||
dt: 时间增量
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return
|
||
|
||
current_time = time.time()
|
||
|
||
# 检查连接超时
|
||
if current_time - self.last_connection_check >= 1.0: # 每秒检查一次
|
||
self._check_connection_timeouts(current_time)
|
||
self.last_connection_check = current_time
|
||
|
||
# 检查心跳超时
|
||
if current_time - self.last_heartbeat_check >= self.connection_config['heartbeat_interval']:
|
||
self._check_heartbeat_timeouts(current_time)
|
||
self.last_heartbeat_check = current_time
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接管理器更新失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def _check_connection_timeouts(self, current_time: float):
|
||
"""
|
||
检查连接超时
|
||
|
||
Args:
|
||
current_time: 当前时间
|
||
"""
|
||
try:
|
||
timeout_clients = []
|
||
for client_id, client_data in self.clients.items():
|
||
connect_time = client_data.get('connect_time', 0)
|
||
if current_time - connect_time > self.connection_config['connection_timeout']:
|
||
timeout_clients.append(client_id)
|
||
|
||
for client_id in timeout_clients:
|
||
self._disconnect_client(client_id, "timeout")
|
||
self.connection_stats['connections_timed_out'] += 1
|
||
|
||
# 触发连接超时回调
|
||
self._trigger_connection_callback('connection_timeout', {
|
||
'client_id': client_id,
|
||
'reason': 'timeout'
|
||
})
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接超时检查失败: {e}")
|
||
|
||
def _check_heartbeat_timeouts(self, current_time: float):
|
||
"""
|
||
检查心跳超时
|
||
|
||
Args:
|
||
current_time: 当前时间
|
||
"""
|
||
try:
|
||
timeout_clients = []
|
||
for client_id, client_data in self.clients.items():
|
||
last_heartbeat = client_data.get('last_heartbeat', 0)
|
||
if current_time - last_heartbeat > self.connection_config['heartbeat_interval'] * 3:
|
||
timeout_clients.append(client_id)
|
||
|
||
for client_id in timeout_clients:
|
||
self._disconnect_client(client_id, "heartbeat_timeout")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 心跳超时检查失败: {e}")
|
||
|
||
def connect_to_server(self, host: str, port: int = None) -> bool:
|
||
"""
|
||
连接到服务器
|
||
|
||
Args:
|
||
host: 服务器地址
|
||
port: 服务器端口
|
||
|
||
Returns:
|
||
是否连接成功
|
||
"""
|
||
try:
|
||
if self.client_state['is_connected']:
|
||
print("✗ 客户端已连接到服务器")
|
||
return False
|
||
|
||
if port is None:
|
||
port = self.connection_config['server_port']
|
||
|
||
# 更新客户端状态
|
||
self.client_state['server_address'] = host
|
||
self.client_state['server_port'] = port
|
||
self.client_state['connection_time'] = time.time()
|
||
self.client_state['reconnect_attempts'] = 0
|
||
|
||
# 通过网络管理器连接
|
||
if self.plugin.network_manager:
|
||
success = self.plugin.network_manager.connect_to_server(host, port)
|
||
if success:
|
||
self.client_state['is_connected'] = True
|
||
print(f"✓ 已连接到服务器: {host}:{port}")
|
||
return True
|
||
else:
|
||
print("✗ 连接服务器失败")
|
||
return False
|
||
else:
|
||
print("✗ 网络管理器未初始化")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"✗ 连接服务器失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def disconnect_from_server(self):
|
||
"""断开与服务器的连接"""
|
||
try:
|
||
self._disconnect_from_server()
|
||
print("✓ 已断开与服务器的连接")
|
||
except Exception as e:
|
||
print(f"✗ 断开服务器连接失败: {e}")
|
||
|
||
def _disconnect_from_server(self):
|
||
"""内部方法:断开与服务器的连接"""
|
||
try:
|
||
if self.plugin.network_manager:
|
||
self.plugin.network_manager.disconnect_client()
|
||
|
||
self.client_state['is_connected'] = False
|
||
self.client_state['server_address'] = ''
|
||
self.client_state['connection_time'] = 0.0
|
||
|
||
except Exception as e:
|
||
print(f"✗ 服务器断开连接失败: {e}")
|
||
|
||
def add_client(self, client_id: str, client_socket: socket.socket,
|
||
client_address: tuple) -> bool:
|
||
"""
|
||
添加客户端连接
|
||
|
||
Args:
|
||
client_id: 客户端ID
|
||
client_socket: 客户端套接字
|
||
client_address: 客户端地址
|
||
|
||
Returns:
|
||
是否添加成功
|
||
"""
|
||
try:
|
||
client_ip = client_address[0]
|
||
|
||
# 检查IP是否被禁止
|
||
if client_ip in self.banned_ips:
|
||
self.connection_stats['banned_connections'] += 1
|
||
client_socket.close()
|
||
|
||
# 触发连接禁止回调
|
||
self._trigger_connection_callback('connection_banned', {
|
||
'client_id': client_id,
|
||
'ip': client_ip,
|
||
'address': client_address
|
||
})
|
||
|
||
return False
|
||
|
||
# 检查连接限制
|
||
if self.connection_config['enable_connection_limits']:
|
||
ip_connections = sum(1 for client in self.clients.values()
|
||
if client.get('address', ('', 0))[0] == client_ip)
|
||
if ip_connections >= self.connection_config['max_connections_per_ip']:
|
||
self.connection_stats['connections_rejected'] += 1
|
||
client_socket.close()
|
||
return False
|
||
|
||
# 检查最大连接数
|
||
if (self.connection_config['enable_connection_limits'] and
|
||
len(self.clients) >= self.connection_config['max_connections']):
|
||
self.connection_stats['connections_rejected'] += 1
|
||
client_socket.close()
|
||
return False
|
||
|
||
# 添加客户端
|
||
self.clients[client_id] = {
|
||
'socket': client_socket,
|
||
'address': client_address,
|
||
'connect_time': time.time(),
|
||
'last_heartbeat': time.time(),
|
||
'bytes_sent': 0,
|
||
'bytes_received': 0,
|
||
'ping': 0.0
|
||
}
|
||
|
||
# 更新服务器状态
|
||
self.server_state['clients_connected'] = len(self.clients)
|
||
if len(self.clients) > self.server_state['peak_connections']:
|
||
self.server_state['peak_connections'] = len(self.clients)
|
||
|
||
self.connection_stats['connections_accepted'] += 1
|
||
|
||
# 触发客户端连接回调
|
||
self._trigger_connection_callback('client_connected', {
|
||
'client_id': client_id,
|
||
'address': client_address
|
||
})
|
||
|
||
print(f"✓ 客户端已连接: {client_id} ({client_address})")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 添加客户端失败: {e}")
|
||
self.connection_stats['connections_rejected'] += 1
|
||
return False
|
||
|
||
def remove_client(self, client_id: str, reason: str = "unknown"):
|
||
"""
|
||
移除客户端连接
|
||
|
||
Args:
|
||
client_id: 客户端ID
|
||
reason: 断开原因
|
||
"""
|
||
try:
|
||
if client_id in self.clients:
|
||
client_data = self.clients[client_id]
|
||
|
||
# 关闭套接字
|
||
try:
|
||
client_data['socket'].close()
|
||
except Exception as e:
|
||
pass
|
||
|
||
# 移除客户端
|
||
del self.clients[client_id]
|
||
|
||
# 更新服务器状态
|
||
self.server_state['clients_connected'] = len(self.clients)
|
||
|
||
self.connection_stats['connections_lost'] += 1
|
||
|
||
# 触发客户端断开连接回调
|
||
self._trigger_connection_callback('client_disconnected', {
|
||
'client_id': client_id,
|
||
'reason': reason
|
||
})
|
||
|
||
print(f"✓ 客户端已断开: {client_id} (原因: {reason})")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 移除客户端失败: {e}")
|
||
|
||
def _disconnect_client(self, client_id: str, reason: str = "unknown"):
|
||
"""
|
||
断开客户端连接
|
||
|
||
Args:
|
||
client_id: 客户端ID
|
||
reason: 断开原因
|
||
"""
|
||
self.remove_client(client_id, reason)
|
||
|
||
def _disconnect_all_clients(self):
|
||
"""断开所有客户端连接"""
|
||
try:
|
||
client_ids = list(self.clients.keys())
|
||
for client_id in client_ids:
|
||
self._disconnect_client(client_id, "server_shutdown")
|
||
except Exception as e:
|
||
print(f"✗ 断开所有客户端连接失败: {e}")
|
||
|
||
def send_heartbeat(self, client_id: str = None):
|
||
"""
|
||
发送心跳包
|
||
|
||
Args:
|
||
client_id: 客户端ID(None表示服务器发送给所有客户端)
|
||
"""
|
||
try:
|
||
heartbeat_data = {
|
||
'timestamp': time.time()
|
||
}
|
||
|
||
if client_id:
|
||
# 发送给特定客户端
|
||
if self.plugin.protocol_handler:
|
||
self.plugin.protocol_handler.send_message('HEARTBEAT', heartbeat_data, client_id)
|
||
else:
|
||
# 发送给所有客户端
|
||
if self.plugin.protocol_handler:
|
||
for cid in self.clients.keys():
|
||
self.plugin.protocol_handler.send_message('HEARTBEAT', heartbeat_data, cid)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 心跳包发送失败: {e}")
|
||
|
||
def handle_heartbeat(self, client_id: str, data: Dict[str, Any]):
|
||
"""
|
||
处理心跳包
|
||
|
||
Args:
|
||
client_id: 客户端ID
|
||
data: 心跳数据
|
||
"""
|
||
try:
|
||
if client_id in self.clients:
|
||
self.clients[client_id]['last_heartbeat'] = time.time()
|
||
self.clients[client_id]['ping'] = time.time() - data.get('timestamp', time.time())
|
||
except Exception as e:
|
||
print(f"✗ 心跳包处理失败: {e}")
|
||
|
||
def ban_ip(self, ip_address: str):
|
||
"""
|
||
禁止IP地址
|
||
|
||
Args:
|
||
ip_address: IP地址
|
||
"""
|
||
try:
|
||
self.banned_ips.add(ip_address)
|
||
print(f"✓ IP地址已被禁止: {ip_address}")
|
||
|
||
# 断开该IP的所有连接
|
||
clients_to_disconnect = [
|
||
client_id for client_id, client_data in self.clients.items()
|
||
if client_data.get('address', ('', 0))[0] == ip_address
|
||
]
|
||
|
||
for client_id in clients_to_disconnect:
|
||
self._disconnect_client(client_id, "banned")
|
||
|
||
except Exception as e:
|
||
print(f"✗ IP禁止失败: {e}")
|
||
|
||
def unban_ip(self, ip_address: str):
|
||
"""
|
||
解除IP地址禁止
|
||
|
||
Args:
|
||
ip_address: IP地址
|
||
"""
|
||
try:
|
||
if ip_address in self.banned_ips:
|
||
self.banned_ips.remove(ip_address)
|
||
print(f"✓ IP地址禁止已解除: {ip_address}")
|
||
except Exception as e:
|
||
print(f"✗ IP解除禁止失败: {e}")
|
||
|
||
def get_clients(self) -> Dict[str, Any]:
|
||
"""
|
||
获取所有客户端信息
|
||
|
||
Returns:
|
||
客户端信息字典
|
||
"""
|
||
try:
|
||
return {k: v.copy() for k, v in self.clients.items()}
|
||
except Exception as e:
|
||
print(f"✗ 客户端信息获取失败: {e}")
|
||
return {}
|
||
|
||
def get_client_count(self) -> int:
|
||
"""
|
||
获取客户端数量
|
||
|
||
Returns:
|
||
客户端数量
|
||
"""
|
||
return len(self.clients)
|
||
|
||
def get_banned_ips(self) -> List[str]:
|
||
"""
|
||
获取被禁止的IP地址列表
|
||
|
||
Returns:
|
||
被禁止的IP地址列表
|
||
"""
|
||
return list(self.banned_ips)
|
||
|
||
def is_client_connected(self, client_id: str) -> bool:
|
||
"""
|
||
检查客户端是否连接
|
||
|
||
Args:
|
||
client_id: 客户端ID
|
||
|
||
Returns:
|
||
客户端是否连接
|
||
"""
|
||
return client_id in self.clients
|
||
|
||
def get_server_state(self) -> Dict[str, Any]:
|
||
"""
|
||
获取服务器状态
|
||
|
||
Returns:
|
||
服务器状态字典
|
||
"""
|
||
return self.server_state.copy()
|
||
|
||
def get_client_state(self) -> Dict[str, Any]:
|
||
"""
|
||
获取客户端状态
|
||
|
||
Returns:
|
||
客户端状态字典
|
||
"""
|
||
return self.client_state.copy()
|
||
|
||
def get_connection_stats(self) -> Dict[str, Any]:
|
||
"""
|
||
获取连接统计信息
|
||
|
||
Returns:
|
||
连接统计字典
|
||
"""
|
||
return self.connection_stats.copy()
|
||
|
||
def reset_connection_stats(self):
|
||
"""重置连接统计信息"""
|
||
try:
|
||
self.connection_stats = {
|
||
'connections_accepted': 0,
|
||
'connections_rejected': 0,
|
||
'connections_lost': 0,
|
||
'connections_timed_out': 0,
|
||
'reconnections': 0,
|
||
'banned_connections': 0
|
||
}
|
||
print("✓ 连接统计信息已重置")
|
||
except Exception as e:
|
||
print(f"✗ 连接统计信息重置失败: {e}")
|
||
|
||
def set_connection_config(self, config: Dict[str, Any]) -> bool:
|
||
"""
|
||
设置连接配置
|
||
|
||
Args:
|
||
config: 连接配置字典
|
||
|
||
Returns:
|
||
是否设置成功
|
||
"""
|
||
try:
|
||
self.connection_config.update(config)
|
||
print(f"✓ 连接配置已更新: {self.connection_config}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"✗ 连接配置设置失败: {e}")
|
||
return False
|
||
|
||
def get_connection_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取连接配置
|
||
|
||
Returns:
|
||
连接配置字典
|
||
"""
|
||
return self.connection_config.copy()
|
||
|
||
def _trigger_connection_callback(self, callback_type: str, data: Dict[str, Any]):
|
||
"""
|
||
触发连接回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
data: 回调数据
|
||
"""
|
||
try:
|
||
if callback_type in self.connection_callbacks:
|
||
for callback in self.connection_callbacks[callback_type]:
|
||
try:
|
||
callback(data)
|
||
except Exception as e:
|
||
print(f"✗ 连接回调执行失败: {e}")
|
||
except Exception as e:
|
||
print(f"✗ 连接回调触发失败: {e}")
|
||
|
||
def register_connection_callback(self, callback_type: str, callback: callable):
|
||
"""
|
||
注册连接回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
callback: 回调函数
|
||
"""
|
||
try:
|
||
if callback_type in self.connection_callbacks:
|
||
self.connection_callbacks[callback_type].append(callback)
|
||
print(f"✓ 连接回调已注册: {callback_type}")
|
||
else:
|
||
print(f"✗ 无效的回调类型: {callback_type}")
|
||
except Exception as e:
|
||
print(f"✗ 连接回调注册失败: {e}")
|
||
|
||
def unregister_connection_callback(self, callback_type: str, callback: callable):
|
||
"""
|
||
注销连接回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
callback: 回调函数
|
||
"""
|
||
try:
|
||
if callback_type in self.connection_callbacks:
|
||
if callback in self.connection_callbacks[callback_type]:
|
||
self.connection_callbacks[callback_type].remove(callback)
|
||
print(f"✓ 连接回调已注销: {callback_type}")
|
||
except Exception as e:
|
||
print(f"✗ 连接回调注销失败: {e}") |