242 lines
7.1 KiB
GDScript
242 lines
7.1 KiB
GDScript
extends Node
|
||
class_name NetworkManager
|
||
## 网络管理器
|
||
## 负责管理客户端与服务器的 WebSocket 连接
|
||
|
||
# 信号定义
|
||
signal connected_to_server()
|
||
signal disconnected_from_server()
|
||
signal connection_error(error: String)
|
||
signal message_received(message: Dictionary)
|
||
|
||
# 安全管理器
|
||
var security_manager: SecurityManager
|
||
var rate_limiter: RateLimiter
|
||
|
||
# WebSocket 客户端
|
||
var _client: WebSocketPeer = null
|
||
var _server_url: String = "ws://localhost:8080"
|
||
var _is_connected: bool = false
|
||
|
||
# 重连相关
|
||
var _reconnect_attempts: int = 0
|
||
var _max_reconnect_attempts: int = 5
|
||
var _reconnect_delay: float = 1.0
|
||
var _reconnect_timer: float = 0.0
|
||
var _should_reconnect: bool = false
|
||
|
||
# 连接超时相关
|
||
var _connection_timeout: float = 10.0
|
||
var _connection_timer: float = 0.0
|
||
var _is_connecting: bool = false
|
||
|
||
func _ready():
|
||
"""初始化网络管理器"""
|
||
# 使用默认网络设置(避免GameConfig依赖)
|
||
_max_reconnect_attempts = 3
|
||
_reconnect_delay = 1.0
|
||
_connection_timeout = 10.0
|
||
|
||
# 初始化安全组件
|
||
security_manager = SecurityManager.new()
|
||
add_child(security_manager)
|
||
|
||
rate_limiter = RateLimiter.new()
|
||
add_child(rate_limiter)
|
||
|
||
print("[NETWORK] NetworkManager initialized")
|
||
|
||
func connect_to_server(url: String = "") -> void:
|
||
"""连接到服务器"""
|
||
if not url.is_empty():
|
||
_server_url = url
|
||
|
||
print("[NETWORK] Connecting to server: ", _server_url)
|
||
|
||
# 如果已经在连接中,先断开
|
||
if _is_connecting:
|
||
disconnect_from_server()
|
||
|
||
_client = WebSocketPeer.new()
|
||
var err = _client.connect_to_url(_server_url)
|
||
|
||
if err != OK:
|
||
var error_msg = "连接失败: " + str(err)
|
||
print("[NETWORK] Failed to connect: ", err)
|
||
connection_error.emit(error_msg)
|
||
return
|
||
|
||
# 开始连接超时计时
|
||
_is_connecting = true
|
||
_connection_timer = _connection_timeout
|
||
print("[NETWORK] Connection initiated (timeout: ", _connection_timeout, "s)")
|
||
|
||
func disconnect_from_server() -> void:
|
||
"""断开服务器连接"""
|
||
if _client:
|
||
_client.close()
|
||
_client = null
|
||
_is_connected = false
|
||
_is_connecting = false
|
||
_connection_timer = 0.0
|
||
print("Disconnected from server")
|
||
disconnected_from_server.emit()
|
||
|
||
func send_message(message: Dictionary) -> void:
|
||
"""发送消息到服务器(使用消息协议)"""
|
||
if not _is_connected or not _client:
|
||
print("Cannot send message: not connected")
|
||
return
|
||
|
||
# 速率限制检查
|
||
var client_id = "local_client" # 本地客户端标识
|
||
if not rate_limiter.is_message_allowed(client_id):
|
||
print("[WARNING] [NETWORK] Message blocked by rate limiter")
|
||
return
|
||
|
||
# 安全验证消息格式
|
||
if not SecurityManager.validate_message_format(message):
|
||
print("[ERROR] [NETWORK] Invalid message format blocked: ", message.get("type", "unknown"))
|
||
return
|
||
|
||
# 使用 MessageProtocol 序列化
|
||
var json_string = MessageProtocol.serialize(message)
|
||
_client.send_text(json_string)
|
||
print("Sent message: ", message.get("type", "unknown"))
|
||
|
||
func send_typed_message(type: MessageProtocol.MessageType, data: Dictionary = {}) -> void:
|
||
"""发送指定类型的消息"""
|
||
var message = MessageProtocol.create_message(type, data)
|
||
send_message(message)
|
||
|
||
func is_server_connected() -> bool:
|
||
"""检查是否已连接到服务器"""
|
||
return _is_connected
|
||
|
||
func _process(delta):
|
||
"""处理网络消息和重连逻辑"""
|
||
# 处理重连计时器
|
||
if _should_reconnect and _reconnect_timer > 0:
|
||
_reconnect_timer -= delta
|
||
if _reconnect_timer <= 0:
|
||
_attempt_reconnect()
|
||
|
||
# 处理连接超时
|
||
if _is_connecting and _connection_timer > 0:
|
||
_connection_timer -= delta
|
||
if _connection_timer <= 0:
|
||
_handle_connection_timeout()
|
||
return
|
||
|
||
if not _client:
|
||
return
|
||
|
||
_client.poll()
|
||
var state = _client.get_ready_state()
|
||
|
||
# 检查连接状态
|
||
if state == WebSocketPeer.STATE_OPEN:
|
||
if not _is_connected:
|
||
_is_connected = true
|
||
_is_connecting = false # 连接成功,停止超时计时
|
||
_connection_timer = 0.0
|
||
_reconnect_attempts = 0 # 重置重连计数
|
||
_should_reconnect = false
|
||
print("Connected to server!")
|
||
connected_to_server.emit()
|
||
|
||
# 接收消息
|
||
while _client.get_available_packet_count() > 0:
|
||
var packet = _client.get_packet()
|
||
var json_string = packet.get_string_from_utf8()
|
||
|
||
# 检查消息长度(防止DoS攻击)
|
||
if json_string.length() > 10000: # 10KB限制
|
||
print("[ERROR] [NETWORK] Message too large, potential DoS attack. Size: ", json_string.length())
|
||
continue
|
||
|
||
# 使用 MessageProtocol 反序列化
|
||
var message = MessageProtocol.deserialize(json_string)
|
||
|
||
if not message.is_empty():
|
||
# 验证消息格式(基础验证)
|
||
if MessageProtocol.validate_message(message):
|
||
# 安全验证消息格式(增强验证)
|
||
if SecurityManager.validate_message_format(message):
|
||
print("Received message: ", message.get("type", "unknown"))
|
||
message_received.emit(message)
|
||
else:
|
||
print("[ERROR] [NETWORK] Security validation failed for message: ", message.get("type", "unknown"))
|
||
else:
|
||
print("[ERROR] [NETWORK] Invalid message format: ", json_string)
|
||
else:
|
||
print("[ERROR] [NETWORK] Failed to parse message: ", json_string)
|
||
|
||
elif state == WebSocketPeer.STATE_CLOSING:
|
||
pass
|
||
|
||
elif state == WebSocketPeer.STATE_CLOSED:
|
||
if _is_connected:
|
||
_is_connected = false
|
||
print("Connection closed")
|
||
disconnected_from_server.emit()
|
||
|
||
# 触发重连
|
||
_trigger_reconnect()
|
||
elif _is_connecting:
|
||
# 连接过程中关闭,可能是连接失败
|
||
_handle_connection_failure()
|
||
_client = null
|
||
|
||
func _trigger_reconnect() -> void:
|
||
"""触发重连逻辑"""
|
||
if _reconnect_attempts < _max_reconnect_attempts:
|
||
_should_reconnect = true
|
||
# 指数退避:1秒、2秒、4秒
|
||
_reconnect_timer = _reconnect_delay * pow(2, _reconnect_attempts)
|
||
print("Will attempt reconnect in ", _reconnect_timer, " seconds (attempt ", _reconnect_attempts + 1, "/", _max_reconnect_attempts, ")")
|
||
else:
|
||
print("Max reconnect attempts reached")
|
||
connection_error.emit("Failed to reconnect after " + str(_max_reconnect_attempts) + " attempts")
|
||
|
||
func _attempt_reconnect() -> void:
|
||
"""尝试重新连接"""
|
||
_reconnect_attempts += 1
|
||
print("Attempting to reconnect... (attempt ", _reconnect_attempts, "/", _max_reconnect_attempts, ")")
|
||
connect_to_server()
|
||
|
||
func reset_reconnect() -> void:
|
||
"""重置重连状态"""
|
||
_reconnect_attempts = 0
|
||
_should_reconnect = false
|
||
_reconnect_timer = 0.0
|
||
|
||
func _handle_connection_timeout() -> void:
|
||
"""处理连接超时"""
|
||
print("[ERROR] [NETWORK] Connection timeout after ", _connection_timeout, " seconds")
|
||
_is_connecting = false
|
||
_connection_timer = 0.0
|
||
|
||
# 关闭WebSocketPeer连接
|
||
if _client:
|
||
_client.close()
|
||
_client = null
|
||
|
||
connection_error.emit("连接超时:无法连接到服务器,请检查服务器是否启动")
|
||
|
||
func _handle_connection_failure() -> void:
|
||
"""处理连接失败"""
|
||
print("[ERROR] [NETWORK] Connection failed during handshake")
|
||
_is_connecting = false
|
||
_connection_timer = 0.0
|
||
|
||
connection_error.emit("连接失败:服务器拒绝连接或服务器未启动")
|
||
|
||
func set_connection_timeout(timeout: float) -> void:
|
||
"""设置连接超时时间"""
|
||
_connection_timeout = timeout
|
||
|
||
func get_connection_timeout() -> float:
|
||
"""获取连接超时时间"""
|
||
return _connection_timeout
|