# 消息处理机制 ## 🎯 学习目标 通过本章学习,您将能够: - 理解消息处理的完整流程和架构 - 掌握消息路由、验证、存储的实现方法 - 学会设计高效的消息处理系统 - 在Chat-Room项目中应用消息处理技术 ## 🔄 消息处理流程 ### 消息处理架构 ```mermaid graph TB subgraph "消息处理流水线" A[接收消息] --> B[消息解析] B --> C[格式验证] C --> D[权限检查] D --> E[业务处理] E --> F[消息存储] F --> G[消息路由] G --> H[发送响应] end subgraph "处理组件" I[消息解析器
MessageParser] J[验证器
MessageValidator] K[权限管理器
PermissionManager] L[业务处理器
BusinessHandler] M[存储管理器
StorageManager] N[路由器
MessageRouter] end B --> I C --> J D --> K E --> L F --> M G --> N style A fill:#e8f5e8 style H fill:#f8d7da ``` ### Chat-Room消息处理核心 ```python # server/core/message_processor.py - 消息处理器 import json import time from typing import Dict, Any, Optional, List, Callable from dataclasses import dataclass from enum import Enum class ProcessingResult(Enum): """处理结果枚举""" SUCCESS = "success" FAILED = "failed" REJECTED = "rejected" RETRY = "retry" @dataclass class MessageContext: """消息处理上下文""" client_socket: Any # Socket连接 client_address: tuple # 客户端地址 user_id: Optional[int] = None # 用户ID session_token: Optional[str] = None # 会话令牌 processing_start_time: float = None # 处理开始时间 def __post_init__(self): if self.processing_start_time is None: self.processing_start_time = time.time() class MessageProcessor: """ 消息处理器 负责处理所有类型的消息,实现完整的处理流水线 """ def __init__(self, user_manager, chat_manager, storage_manager): self.user_manager = user_manager self.chat_manager = chat_manager self.storage_manager = storage_manager # 消息处理器映射 self.message_handlers: Dict[str, Callable] = { "login_request": self._handle_login_request, "logout_request": self._handle_logout_request, "chat_message": self._handle_chat_message, "private_message": self._handle_private_message, "group_join": self._handle_group_join, "group_leave": self._handle_group_leave, "user_list": self._handle_user_list_request, "heartbeat": self._handle_heartbeat, "file_upload": self._handle_file_upload, } # 处理统计 self.processing_stats = { "total_messages": 0, "successful_messages": 0, "failed_messages": 0, "average_processing_time": 0.0 } def process_message(self, raw_message: bytes, context: MessageContext) -> ProcessingResult: """ 处理消息的主入口 Args: raw_message: 原始消息字节 context: 消息处理上下文 Returns: 处理结果 """ try: # 1. 消息解析 message = self._parse_message(raw_message) if not message: return ProcessingResult.FAILED # 2. 格式验证 if not self._validate_message_format(message): self._send_error_response(context, "INVALID_FORMAT", "消息格式错误") return ProcessingResult.REJECTED # 3. 权限检查 if not self._check_permissions(message, context): self._send_error_response(context, "PERMISSION_DENIED", "权限不足") return ProcessingResult.REJECTED # 4. 业务处理 result = self._handle_business_logic(message, context) # 5. 更新统计信息 self._update_processing_stats(context, result) return result except Exception as e: print(f"消息处理异常: {e}") self._send_error_response(context, "INTERNAL_ERROR", "服务器内部错误") return ProcessingResult.FAILED def _parse_message(self, raw_message: bytes) -> Optional[Dict[str, Any]]: """ 解析原始消息 将字节流解析为JSON消息对象 """ try: # 假设消息格式:[4字节长度][JSON数据] if len(raw_message) < 4: return None # 解析长度 import struct length = struct.unpack('!I', raw_message[:4])[0] if len(raw_message) < 4 + length: return None # 解析JSON json_data = raw_message[4:4+length].decode('utf-8') message = json.loads(json_data) return message except Exception as e: print(f"消息解析失败: {e}") return None def _validate_message_format(self, message: Dict[str, Any]) -> bool: """ 验证消息格式 检查消息是否包含必需字段和正确的数据类型 """ # 检查必需字段 required_fields = ["type", "version"] for field in required_fields: if field not in message: print(f"缺少必需字段: {field}") return False # 检查消息类型 message_type = message.get("type") if not isinstance(message_type, str) or not message_type.strip(): print("消息类型无效") return False # 检查版本 version = message.get("version") if not isinstance(version, str): print("版本格式无效") return False # 根据消息类型进行特定验证 return self._validate_message_by_type(message) def _validate_message_by_type(self, message: Dict[str, Any]) -> bool: """根据消息类型进行特定验证""" message_type = message.get("type") if message_type == "chat_message": # 聊天消息验证 required = ["content", "sender_id"] for field in required: if field not in message: return False # 内容长度检查 content = message.get("content", "") if len(content) > 1000: # 限制1000字符 return False elif message_type == "login_request": # 登录请求验证 required = ["username", "password"] for field in required: if field not in message or not message[field]: return False elif message_type == "private_message": # 私聊消息验证 required = ["content", "sender_id", "target_user_id"] for field in required: if field not in message: return False return True def _check_permissions(self, message: Dict[str, Any], context: MessageContext) -> bool: """ 检查用户权限 验证用户是否有权限执行特定操作 """ message_type = message.get("type") # 不需要认证的消息类型 public_messages = ["login_request", "register_request", "heartbeat"] if message_type in public_messages: return True # 需要认证的消息类型 if not context.user_id: print("用户未认证") return False # 检查用户是否被禁用 if self.user_manager.is_user_banned(context.user_id): print(f"用户 {context.user_id} 已被禁用") return False # 根据消息类型检查特定权限 return self._check_specific_permissions(message, context) def _check_specific_permissions(self, message: Dict[str, Any], context: MessageContext) -> bool: """检查特定权限""" message_type = message.get("type") user_id = context.user_id if message_type == "group_join": # 检查是否可以加入群组 group_id = message.get("group_id") return self.chat_manager.can_join_group(user_id, group_id) elif message_type == "private_message": # 检查是否可以发送私聊 target_user_id = message.get("target_user_id") return self.user_manager.can_send_private_message(user_id, target_user_id) elif message_type == "admin_command": # 检查管理员权限 return self.user_manager.is_admin(user_id) return True def _handle_business_logic(self, message: Dict[str, Any], context: MessageContext) -> ProcessingResult: """ 处理业务逻辑 根据消息类型调用相应的处理器 """ message_type = message.get("type") if message_type in self.message_handlers: try: handler = self.message_handlers[message_type] return handler(message, context) except Exception as e: print(f"业务处理异常: {e}") return ProcessingResult.FAILED else: print(f"未知消息类型: {message_type}") self._send_error_response(context, "UNKNOWN_MESSAGE_TYPE", f"未知消息类型: {message_type}") return ProcessingResult.REJECTED def _handle_login_request(self, message: Dict[str, Any], context: MessageContext) -> ProcessingResult: """处理登录请求""" username = message.get("username") password = message.get("password") # 验证用户凭据 auth_result = self.user_manager.authenticate_user(username, password) if auth_result.success: # 登录成功 context.user_id = auth_result.user_id context.session_token = auth_result.token # 发送成功响应 response = { "type": "login_response", "success": True, "user_id": auth_result.user_id, "token": auth_result.token, "message": "登录成功" } self._send_response(context, response) # 广播用户上线消息 self.chat_manager.broadcast_user_status(auth_result.user_id, "online") return ProcessingResult.SUCCESS else: # 登录失败 response = { "type": "login_response", "success": False, "message": auth_result.message } self._send_response(context, response) return ProcessingResult.REJECTED def _handle_chat_message(self, message: Dict[str, Any], context: MessageContext) -> ProcessingResult: """处理聊天消息""" sender_id = context.user_id content = message.get("content") group_id = message.get("group_id", 1) # 默认公频 # 创建聊天消息对象 chat_message = { "type": "chat_message", "message_id": self._generate_message_id(), "sender_id": sender_id, "sender_name": self.user_manager.get_username(sender_id), "content": content, "group_id": group_id, "timestamp": time.time() } # 存储消息 self.storage_manager.save_message(chat_message) # 广播消息给群组成员 self.chat_manager.broadcast_to_group(group_id, chat_message, exclude_user=sender_id) # 发送确认响应 ack_response = { "type": "message_ack", "message_id": chat_message["message_id"], "status": "delivered" } self._send_response(context, ack_response) return ProcessingResult.SUCCESS def _handle_private_message(self, message: Dict[str, Any], context: MessageContext) -> ProcessingResult: """处理私聊消息""" sender_id = context.user_id target_user_id = message.get("target_user_id") content = message.get("content") # 检查目标用户是否存在且在线 if not self.user_manager.is_user_online(target_user_id): self._send_error_response(context, "USER_OFFLINE", "目标用户不在线") return ProcessingResult.REJECTED # 创建私聊消息 private_message = { "type": "private_message", "message_id": self._generate_message_id(), "sender_id": sender_id, "sender_name": self.user_manager.get_username(sender_id), "target_user_id": target_user_id, "content": content, "timestamp": time.time() } # 存储消息 self.storage_manager.save_private_message(private_message) # 发送给目标用户 self.chat_manager.send_to_user(target_user_id, private_message) # 发送确认响应 ack_response = { "type": "message_ack", "message_id": private_message["message_id"], "status": "delivered" } self._send_response(context, ack_response) return ProcessingResult.SUCCESS def _handle_heartbeat(self, message: Dict[str, Any], context: MessageContext) -> ProcessingResult: """处理心跳消息""" # 更新用户活动时间 if context.user_id: self.user_manager.update_user_activity(context.user_id) # 发送心跳响应 pong_response = { "type": "heartbeat_response", "timestamp": time.time(), "server_time": time.time() } self._send_response(context, pong_response) return ProcessingResult.SUCCESS def _send_response(self, context: MessageContext, response: Dict[str, Any]): """发送响应消息""" try: # 编码响应 response_json = json.dumps(response, ensure_ascii=False) response_bytes = response_json.encode('utf-8') # 添加长度头 import struct length_header = struct.pack('!I', len(response_bytes)) # 发送响应 context.client_socket.send(length_header + response_bytes) except Exception as e: print(f"发送响应失败: {e}") def _send_error_response(self, context: MessageContext, error_code: str, error_message: str): """发送错误响应""" error_response = { "type": "error_response", "error_code": error_code, "error_message": error_message, "timestamp": time.time() } self._send_response(context, error_response) def _generate_message_id(self) -> str: """生成消息ID""" import uuid return str(uuid.uuid4()) def _update_processing_stats(self, context: MessageContext, result: ProcessingResult): """更新处理统计信息""" self.processing_stats["total_messages"] += 1 if result == ProcessingResult.SUCCESS: self.processing_stats["successful_messages"] += 1 else: self.processing_stats["failed_messages"] += 1 # 计算处理时间 processing_time = time.time() - context.processing_start_time # 更新平均处理时间 total = self.processing_stats["total_messages"] current_avg = self.processing_stats["average_processing_time"] new_avg = (current_avg * (total - 1) + processing_time) / total self.processing_stats["average_processing_time"] = new_avg def get_processing_stats(self) -> Dict[str, Any]: """获取处理统计信息""" return self.processing_stats.copy() ``` ## 📨 消息路由系统 ### 消息路由器实现 ```python # server/core/message_router.py - 消息路由器 from typing import Dict, List, Set, Optional import threading class MessageRouter: """ 消息路由器 负责将消息路由到正确的目标用户或群组 """ def __init__(self): # 用户连接映射:{user_id: socket} self.user_connections: Dict[int, Any] = {} # 群组成员映射:{group_id: {user_ids}} self.group_members: Dict[int, Set[int]] = {} # 在线用户集合 self.online_users: Set[int] = set() # 线程锁 self.connections_lock = threading.RLock() self.groups_lock = threading.RLock() def register_user_connection(self, user_id: int, socket_connection): """注册用户连接""" with self.connections_lock: self.user_connections[user_id] = socket_connection self.online_users.add(user_id) print(f"用户 {user_id} 连接已注册") def unregister_user_connection(self, user_id: int): """注销用户连接""" with self.connections_lock: if user_id in self.user_connections: del self.user_connections[user_id] self.online_users.discard(user_id) print(f"用户 {user_id} 连接已注销") def add_user_to_group(self, user_id: int, group_id: int): """添加用户到群组""" with self.groups_lock: if group_id not in self.group_members: self.group_members[group_id] = set() self.group_members[group_id].add(user_id) print(f"用户 {user_id} 已加入群组 {group_id}") def remove_user_from_group(self, user_id: int, group_id: int): """从群组移除用户""" with self.groups_lock: if group_id in self.group_members: self.group_members[group_id].discard(user_id) if not self.group_members[group_id]: del self.group_members[group_id] print(f"用户 {user_id} 已离开群组 {group_id}") def route_to_user(self, target_user_id: int, message: Dict[str, Any]) -> bool: """路由消息到指定用户""" with self.connections_lock: if target_user_id not in self.user_connections: print(f"用户 {target_user_id} 不在线") return False try: socket_conn = self.user_connections[target_user_id] self._send_message_to_socket(socket_conn, message) return True except Exception as e: print(f"发送消息给用户 {target_user_id} 失败: {e}") # 移除失效连接 self.unregister_user_connection(target_user_id) return False def route_to_group(self, group_id: int, message: Dict[str, Any], exclude_user: int = None) -> int: """ 路由消息到群组 Returns: 成功发送的用户数量 """ with self.groups_lock: if group_id not in self.group_members: print(f"群组 {group_id} 不存在") return 0 members = self.group_members[group_id].copy() # 排除指定用户 if exclude_user: members.discard(exclude_user) success_count = 0 failed_users = [] for user_id in members: if self.route_to_user(user_id, message): success_count += 1 else: failed_users.append(user_id) # 清理失效用户 if failed_users: with self.groups_lock: for user_id in failed_users: self.group_members[group_id].discard(user_id) return success_count def broadcast_to_all(self, message: Dict[str, Any], exclude_user: int = None) -> int: """广播消息给所有在线用户""" with self.connections_lock: online_users = self.online_users.copy() if exclude_user: online_users.discard(exclude_user) success_count = 0 for user_id in online_users: if self.route_to_user(user_id, message): success_count += 1 return success_count def _send_message_to_socket(self, socket_conn, message: Dict[str, Any]): """发送消息到Socket连接""" import json import struct # 编码消息 message_json = json.dumps(message, ensure_ascii=False) message_bytes = message_json.encode('utf-8') # 发送长度头和消息体 length_header = struct.pack('!I', len(message_bytes)) socket_conn.send(length_header + message_bytes) def get_online_users(self) -> List[int]: """获取在线用户列表""" with self.connections_lock: return list(self.online_users) def get_group_members(self, group_id: int) -> List[int]: """获取群组成员列表""" with self.groups_lock: if group_id in self.group_members: return list(self.group_members[group_id]) return [] def get_routing_stats(self) -> Dict[str, Any]: """获取路由统计信息""" with self.connections_lock, self.groups_lock: return { "online_users_count": len(self.online_users), "total_groups": len(self.group_members), "total_group_members": sum(len(members) for members in self.group_members.values()), "active_connections": len(self.user_connections) } ``` ## 🎯 实践练习 ### 练习1:消息过滤器 ```python class MessageFilter: """ 消息过滤器练习 要求: 1. 实现垃圾消息过滤 2. 敏感词检测和替换 3. 消息频率限制 4. 内容长度限制 """ def __init__(self): # TODO: 初始化过滤器 pass def filter_spam(self, message: str) -> bool: """过滤垃圾消息""" # TODO: 实现垃圾消息检测 pass def filter_profanity(self, message: str) -> str: """过滤敏感词""" # TODO: 实现敏感词过滤 pass def check_rate_limit(self, user_id: int) -> bool: """检查发送频率限制""" # TODO: 实现频率限制检查 pass ``` ### 练习2:消息队列系统 ```python class MessageQueue: """ 消息队列系统练习 要求: 1. 实现消息队列管理 2. 支持消息优先级 3. 离线消息存储 4. 消息重试机制 """ def __init__(self): # TODO: 初始化消息队列 pass def enqueue_message(self, message: Dict[str, Any], priority: int = 0): """入队消息""" # TODO: 实现消息入队 pass def dequeue_message(self) -> Optional[Dict[str, Any]]: """出队消息""" # TODO: 实现消息出队 pass def store_offline_message(self, user_id: int, message: Dict[str, Any]): """存储离线消息""" # TODO: 实现离线消息存储 pass ``` ## ✅ 学习检查 完成本章学习后,请确认您能够: - [ ] 理解消息处理的完整流程 - [ ] 实现消息解析、验证、路由功能 - [ ] 设计高效的消息路由系统 - [ ] 处理各种类型的消息 - [ ] 实现消息过滤和安全检查 - [ ] 完成实践练习 ## 📚 下一步 消息处理机制掌握后,请继续学习: - [多线程编程基础](threading-basics.md) - [错误处理策略](error-handling.md) --- **现在您已经掌握了消息处理的核心技术!** 🎉