EG/plugins/user/network_sync/protocol/protocol_handler.py
2025-10-30 11:46:41 +08:00

883 lines
30 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
import json
import struct
from typing import Dict, Any, List, Optional
import hashlib
import zlib
class ProtocolHandler:
"""
协议处理器
负责处理各种网络协议和消息格式
"""
def __init__(self, plugin):
"""
初始化协议处理器
Args:
plugin: 网络同步插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 协议配置
self.protocol_config = {
'version': '1.0',
'enable_compression': True,
'compression_level': 6,
'enable_checksum': True,
'max_message_size': 65536, # 64KB
'enable_fragmentation': True,
'fragment_size': 1024,
'enable_encryption': False,
'supported_protocols': ['sync_v1', 'sync_v2']
}
# 消息类型定义
self.message_types = {
'CONNECT': 1,
'CONNECT_ACK': 2,
'DISCONNECT': 3,
'HEARTBEAT': 4,
'SYNC_DATA': 5,
'SYNC_REQUEST': 6,
'SYNC_RESPONSE': 7,
'RPC_CALL': 8,
'RPC_RESPONSE': 9,
'EVENT': 10,
'CHAT': 11,
'ERROR': 12
}
# 消息处理器
self.message_handlers = {}
# 协议状态
self.protocol_state = {
'current_protocol': 'sync_v1',
'bytes_processed': 0,
'messages_processed': 0,
'compression_savings': 0,
'fragmented_messages': 0
}
# 消息片段缓存
self.message_fragments = {}
# 协议统计
self.protocol_stats = {
'messages_sent': 0,
'messages_received': 0,
'bytes_sent': 0,
'bytes_received': 0,
'compressed_messages': 0,
'checksum_errors': 0,
'protocol_errors': 0,
'fragmented_packets': 0
}
# 回调函数
self.protocol_callbacks = {
'message_received': [],
'message_sent': [],
'protocol_error': [],
'message_fragmented': []
}
# 时间戳记录
self.last_protocol_update = 0.0
self.last_compression_savings = 0.0
print("✓ 协议处理器已创建")
def initialize(self) -> bool:
"""
初始化协议处理器
Returns:
是否初始化成功
"""
try:
# 注册默认消息处理器
self._register_default_handlers()
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
print("✓ 协议处理器已启用")
return True
except Exception as e:
print(f"✗ 协议处理器启用失败: {e}")
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用协议处理器"""
try:
self.enabled = False
print("✓ 协议处理器已禁用")
except Exception as e:
print(f"✗ 协议处理器禁用失败: {e}")
import traceback
traceback.print_exc()
def finalize(self):
"""清理协议处理器资源"""
try:
self.disable()
self.message_handlers.clear()
self.message_fragments.clear()
self.protocol_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()
self.last_protocol_update = current_time
# 清理过期的消息片段
self._cleanup_fragments(current_time)
except Exception as e:
print(f"✗ 协议处理器更新失败: {e}")
import traceback
traceback.print_exc()
def _register_default_handlers(self):
"""注册默认消息处理器"""
try:
self.message_handlers = {
self.message_types['CONNECT']: self._handle_connect,
self.message_types['CONNECT_ACK']: self._handle_connect_ack,
self.message_types['DISCONNECT']: self._handle_disconnect,
self.message_types['HEARTBEAT']: self._handle_heartbeat,
self.message_types['SYNC_DATA']: self._handle_sync_data,
self.message_types['SYNC_REQUEST']: self._handle_sync_request,
self.message_types['SYNC_RESPONSE']: self._handle_sync_response,
self.message_types['RPC_CALL']: self._handle_rpc_call,
self.message_types['RPC_RESPONSE']: self._handle_rpc_response,
self.message_types['EVENT']: self._handle_event,
self.message_types['CHAT']: self._handle_chat,
self.message_types['ERROR']: self._handle_error
}
print("✓ 默认消息处理器已注册")
except Exception as e:
print(f"✗ 默认消息处理器注册失败: {e}")
def _cleanup_fragments(self, current_time: float):
"""
清理过期的消息片段
Args:
current_time: 当前时间
"""
try:
expired_fragments = [
msg_id for msg_id, fragment_data in self.message_fragments.items()
if current_time - fragment_data.get('timestamp', 0) > 30.0 # 30秒超时
]
for msg_id in expired_fragments:
del self.message_fragments[msg_id]
except Exception as e:
print(f"✗ 消息片段清理失败: {e}")
def encode_message(self, message_type: str, data: Dict[str, Any],
compress: bool = None, add_checksum: bool = None) -> Optional[bytes]:
"""
编码消息
Args:
message_type: 消息类型
data: 消息数据
compress: 是否压缩
add_checksum: 是否添加校验和
Returns:
编码后的消息数据或None
"""
try:
# 获取消息类型ID
type_id = self.message_types.get(message_type.upper())
if type_id is None:
print(f"✗ 未知的消息类型: {message_type}")
return None
# 序列化数据
data_json = json.dumps(data, ensure_ascii=False)
data_bytes = data_json.encode('utf-8')
original_size = len(data_bytes)
# 压缩数据
compressed = False
if compress is None:
compress = self.protocol_config['enable_compression']
if compress and original_size > 256: # 只压缩大于256字节的数据
compressed_data = zlib.compress(data_bytes, self.protocol_config['compression_level'])
if len(compressed_data) < original_size:
data_bytes = compressed_data
compressed = True
self.protocol_stats['compressed_messages'] += 1
self.protocol_state['compression_savings'] += original_size - len(compressed_data)
# 添加校验和
checksum = b''
if add_checksum is None:
add_checksum = self.protocol_config['enable_checksum']
if add_checksum:
checksum = hashlib.md5(data_bytes).digest()
# 构造消息头
timestamp = int(time.time() * 1000) & 0xFFFFFFFF # 32位时间戳
header = struct.pack('!BBI', type_id, compressed, timestamp)
# 构造完整消息
message = header + checksum + data_bytes
# 更新统计信息
self.protocol_stats['messages_sent'] += 1
self.protocol_stats['bytes_sent'] += len(message)
self.protocol_state['bytes_processed'] += len(message)
self.protocol_state['messages_processed'] += 1
return message
except Exception as e:
print(f"✗ 消息编码失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return None
def decode_message(self, message_data: bytes) -> Optional[Dict[str, Any]]:
"""
解码消息
Args:
message_data: 消息数据
Returns:
解码后的消息字典或None
"""
try:
if len(message_data) < 6: # 最小消息长度(1字节类型+1字节压缩标志+4字节时间戳)
print("✗ 消息数据太短")
self.protocol_stats['protocol_errors'] += 1
return None
# 解析消息头
header_size = 6
type_id, compressed_flag, timestamp = struct.unpack('!BBI', message_data[:header_size])
# 获取消息类型名称
message_type = None
for name, id_val in self.message_types.items():
if id_val == type_id:
message_type = name
break
if message_type is None:
print(f"✗ 未知的消息类型ID: {type_id}")
self.protocol_stats['protocol_errors'] += 1
return None
# 计算校验和偏移
checksum_offset = header_size
if self.protocol_config['enable_checksum']:
checksum_offset += 16 # MD5校验和长度
# 获取数据部分
data_bytes = message_data[checksum_offset:]
# 验证校验和
if self.protocol_config['enable_checksum'] and len(message_data) >= checksum_offset:
expected_checksum = message_data[header_size:checksum_offset]
actual_checksum = hashlib.md5(data_bytes).digest()
if expected_checksum != actual_checksum:
print("✗ 消息校验和错误")
self.protocol_stats['checksum_errors'] += 1
return None
# 解压缩数据
if compressed_flag:
try:
data_bytes = zlib.decompress(data_bytes)
except Exception as e:
print(f"✗ 消息解压缩失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return None
# 反序列化数据
data_json = data_bytes.decode('utf-8')
data = json.loads(data_json)
# 构造解码结果
result = {
'type': message_type,
'type_id': type_id,
'compressed': bool(compressed_flag),
'timestamp': timestamp,
'data': data
}
# 更新统计信息
self.protocol_stats['messages_received'] += 1
self.protocol_stats['bytes_received'] += len(message_data)
self.protocol_state['bytes_processed'] += len(message_data)
self.protocol_state['messages_processed'] += 1
# 触发消息接收回调
self._trigger_protocol_callback('message_received', result)
return result
except Exception as e:
print(f"✗ 消息解码失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return None
def fragment_message(self, message_data: bytes, fragment_size: int = None) -> List[bytes]:
"""
分片消息
Args:
message_data: 消息数据
fragment_size: 分片大小
Returns:
分片后的消息列表
"""
try:
if fragment_size is None:
fragment_size = self.protocol_config['fragment_size']
if len(message_data) <= fragment_size:
return [message_data]
fragments = []
message_id = hashlib.md5(message_data).hexdigest()[:8]
total_fragments = (len(message_data) + fragment_size - 1) // fragment_size
for i in range(total_fragments):
start_pos = i * fragment_size
end_pos = min((i + 1) * fragment_size, len(message_data))
fragment_data = message_data[start_pos:end_pos]
# 构造分片头
fragment_header = struct.pack('!8sHH',
message_id.encode('ascii'),
i,
total_fragments)
fragments.append(fragment_header + fragment_data)
self.protocol_stats['fragmented_packets'] += len(fragments)
self.protocol_state['fragmented_messages'] += 1
# 触发消息分片回调
self._trigger_protocol_callback('message_fragmented', {
'message_id': message_id,
'total_fragments': total_fragments,
'fragment_size': fragment_size
})
return fragments
except Exception as e:
print(f"✗ 消息分片失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return [message_data]
def reassemble_message(self, fragment_data: bytes) -> Optional[bytes]:
"""
重组消息
Args:
fragment_data: 分片数据
Returns:
重组后的消息数据或None
"""
try:
if len(fragment_data) < 12: # 分片头最小长度
return None
# 解析分片头
message_id_bytes, fragment_index, total_fragments = struct.unpack('!8sHH', fragment_data[:12])
message_id = message_id_bytes.decode('ascii').rstrip('\x00')
fragment_payload = fragment_data[12:]
# 初始化分片缓存
if message_id not in self.message_fragments:
self.message_fragments[message_id] = {
'fragments': {},
'total_fragments': total_fragments,
'timestamp': time.time()
}
# 存储分片
self.message_fragments[message_id]['fragments'][fragment_index] = fragment_payload
# 检查是否所有分片都已到达
fragment_cache = self.message_fragments[message_id]
if len(fragment_cache['fragments']) == fragment_cache['total_fragments']:
# 重组消息
message_parts = []
for i in range(fragment_cache['total_fragments']):
if i in fragment_cache['fragments']:
message_parts.append(fragment_cache['fragments'][i])
else:
# 缺少分片
return None
# 清理缓存
del self.message_fragments[message_id]
# 返回重组后的消息
return b''.join(message_parts)
return None
except Exception as e:
print(f"✗ 消息重组失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return None
def send_message(self, message_type: str, data: Dict[str, Any],
target_client_id: str = None) -> bool:
"""
发送消息
Args:
message_type: 消息类型
data: 消息数据
target_client_id: 目标客户端ID
Returns:
是否发送成功
"""
try:
if not self.enabled:
print("✗ 协议处理器未启用")
return False
# 编码消息
message_bytes = self.encode_message(message_type, data)
if message_bytes is None:
print("✗ 消息编码失败")
return False
# 检查是否需要分片
if (self.protocol_config['enable_fragmentation'] and
len(message_bytes) > self.protocol_config['fragment_size']):
fragments = self.fragment_message(message_bytes)
success = True
# 发送所有分片
for fragment in fragments:
if not self._send_raw_message(fragment, target_client_id):
success = False
if success:
# 触发消息发送回调
self._trigger_protocol_callback('message_sent', {
'type': message_type,
'data': data,
'fragmented': True,
'fragment_count': len(fragments)
})
return success
else:
# 发送完整消息
if self._send_raw_message(message_bytes, target_client_id):
# 触发消息发送回调
self._trigger_protocol_callback('message_sent', {
'type': message_type,
'data': data,
'fragmented': False
})
return True
else:
return False
except Exception as e:
print(f"✗ 消息发送失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return False
def _send_raw_message(self, message_bytes: bytes, target_client_id: str = None) -> bool:
"""
发送原始消息数据
Args:
message_bytes: 消息字节数据
target_client_id: 目标客户端ID
Returns:
是否发送成功
"""
try:
# 通过网络管理器发送消息
if self.plugin.network_manager:
# 这里应该调用网络管理器的发送方法
# 由于是模拟实现我们只返回True
return True
else:
print("✗ 网络管理器未初始化")
return False
except Exception as e:
print(f"✗ 原始消息发送失败: {e}")
return False
def receive_message(self, message_bytes: bytes) -> bool:
"""
接收消息
Args:
message_bytes: 消息字节数据
Returns:
是否处理成功
"""
try:
if not self.enabled:
print("✗ 协议处理器未启用")
return False
# 检查是否为分片消息
if len(message_bytes) >= 12:
# 尝试解析分片头
try:
message_id_bytes, fragment_index, total_fragments = struct.unpack('!8sHH', message_bytes[:12])
# 这是一个分片消息
reassembled_message = self.reassemble_message(message_bytes)
if reassembled_message is not None:
# 分片重组完成,处理完整消息
return self.receive_message(reassembled_message)
else:
# 等待更多分片
return True
except struct.error:
# 不是分片消息,继续处理
pass
# 解码消息
decoded_message = self.decode_message(message_bytes)
if decoded_message is None:
print("✗ 消息解码失败")
return False
# 处理消息
return self._process_message(decoded_message)
except Exception as e:
print(f"✗ 消息接收失败: {e}")
self.protocol_stats['protocol_errors'] += 1
return False
def _process_message(self, message: Dict[str, Any]) -> bool:
"""
处理消息
Args:
message: 解码后的消息
Returns:
是否处理成功
"""
try:
message_type_id = message.get('type_id')
message_data = message.get('data', {})
# 查找对应的消息处理器
if message_type_id in self.message_handlers:
handler = self.message_handlers[message_type_id]
return handler(message_data)
else:
print(f"✗ 未找到消息处理器: {message_type_id}")
return False
except Exception as e:
print(f"✗ 消息处理失败: {e}")
return False
# 默认消息处理器
def _handle_connect(self, data: Dict[str, Any]) -> bool:
"""处理连接消息"""
try:
print(f"✓ 处理连接消息: {data}")
return True
except Exception as e:
print(f"✗ 连接消息处理失败: {e}")
return False
def _handle_connect_ack(self, data: Dict[str, Any]) -> bool:
"""处理连接确认消息"""
try:
print(f"✓ 处理连接确认消息: {data}")
return True
except Exception as e:
print(f"✗ 连接确认消息处理失败: {e}")
return False
def _handle_disconnect(self, data: Dict[str, Any]) -> bool:
"""处理断开连接消息"""
try:
print(f"✓ 处理断开连接消息: {data}")
return True
except Exception as e:
print(f"✗ 断开连接消息处理失败: {e}")
return False
def _handle_heartbeat(self, data: Dict[str, Any]) -> bool:
"""处理心跳消息"""
try:
print(f"✓ 处理心跳消息: {data}")
return True
except Exception as e:
print(f"✗ 心跳消息处理失败: {e}")
return False
def _handle_sync_data(self, data: Dict[str, Any]) -> bool:
"""处理同步数据消息"""
try:
print(f"✓ 处理同步数据消息: {len(data)}个对象")
# 传递给对象同步模块
if self.plugin.object_sync:
for obj_id, obj_data in data.items():
self.plugin.object_sync.receive_sync_data(obj_id, obj_data)
return True
except Exception as e:
print(f"✗ 同步数据消息处理失败: {e}")
return False
def _handle_sync_request(self, data: Dict[str, Any]) -> bool:
"""处理同步请求消息"""
try:
print(f"✓ 处理同步请求消息: {data}")
return True
except Exception as e:
print(f"✗ 同步请求消息处理失败: {e}")
return False
def _handle_sync_response(self, data: Dict[str, Any]) -> bool:
"""处理同步响应消息"""
try:
print(f"✓ 处理同步响应消息: {data}")
return True
except Exception as e:
print(f"✗ 同步响应消息处理失败: {e}")
return False
def _handle_rpc_call(self, data: Dict[str, Any]) -> bool:
"""处理RPC调用消息"""
try:
print(f"✓ 处理RPC调用消息: {data}")
return True
except Exception as e:
print(f"✗ RPC调用消息处理失败: {e}")
return False
def _handle_rpc_response(self, data: Dict[str, Any]) -> bool:
"""处理RPC响应消息"""
try:
print(f"✓ 处理RPC响应消息: {data}")
return True
except Exception as e:
print(f"✗ RPC响应消息处理失败: {e}")
return False
def _handle_event(self, data: Dict[str, Any]) -> bool:
"""处理事件消息"""
try:
print(f"✓ 处理事件消息: {data}")
return True
except Exception as e:
print(f"✗ 事件消息处理失败: {e}")
return False
def _handle_chat(self, data: Dict[str, Any]) -> bool:
"""处理聊天消息"""
try:
print(f"✓ 处理聊天消息: {data}")
return True
except Exception as e:
print(f"✗ 聊天消息处理失败: {e}")
return False
def _handle_error(self, data: Dict[str, Any]) -> bool:
"""处理错误消息"""
try:
print(f"✗ 处理错误消息: {data}")
# 触发协议错误回调
self._trigger_protocol_callback('protocol_error', data)
return True
except Exception as e:
print(f"✗ 错误消息处理失败: {e}")
return False
def get_protocol_config(self) -> Dict[str, Any]:
"""
获取协议配置
Returns:
协议配置字典
"""
return self.protocol_config.copy()
def set_protocol_config(self, config: Dict[str, Any]) -> bool:
"""
设置协议配置
Args:
config: 协议配置字典
Returns:
是否设置成功
"""
try:
self.protocol_config.update(config)
print(f"✓ 协议配置已更新: {self.protocol_config}")
return True
except Exception as e:
print(f"✗ 协议配置设置失败: {e}")
return False
def get_protocol_stats(self) -> Dict[str, Any]:
"""
获取协议统计信息
Returns:
协议统计字典
"""
return self.protocol_stats.copy()
def reset_protocol_stats(self):
"""重置协议统计信息"""
try:
self.protocol_stats = {
'messages_sent': 0,
'messages_received': 0,
'bytes_sent': 0,
'bytes_received': 0,
'compressed_messages': 0,
'checksum_errors': 0,
'protocol_errors': 0,
'fragmented_packets': 0
}
print("✓ 协议统计信息已重置")
except Exception as e:
print(f"✗ 协议统计信息重置失败: {e}")
def get_protocol_state(self) -> Dict[str, Any]:
"""
获取协议状态
Returns:
协议状态字典
"""
return self.protocol_state.copy()
def _trigger_protocol_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发协议回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.protocol_callbacks:
for callback in self.protocol_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 协议回调执行失败: {e}")
except Exception as e:
print(f"✗ 协议回调触发失败: {e}")
def register_protocol_callback(self, callback_type: str, callback: callable):
"""
注册协议回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.protocol_callbacks:
self.protocol_callbacks[callback_type].append(callback)
print(f"✓ 协议回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 协议回调注册失败: {e}")
def unregister_protocol_callback(self, callback_type: str, callback: callable):
"""
注销协议回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.protocol_callbacks:
if callback in self.protocol_callbacks[callback_type]:
self.protocol_callbacks[callback_type].remove(callback)
print(f"✓ 协议回调已注销: {callback_type}")
except Exception as e:
print(f"✗ 协议回调注销失败: {e}")