EG/plugins/user/network_sync/connection/connection_manager.py
2025-12-12 16:16:15 +08:00

685 lines
23 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 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: 客户端IDNone表示服务器发送给所有客户端
"""
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}")