|
|
@ -308,56 +308,87 @@ public class WebSocketMiddleware |
|
|
|
{ |
|
|
|
_logger.LogInformation("开始处理 WebSocket 消息,连接ID:{ConnectionId}", connectionId); |
|
|
|
|
|
|
|
// 接收第一条消息
|
|
|
|
var receiveResult = await webSocket.ReceiveAsync( |
|
|
|
new ArraySegment<byte>(buffer), cancellationToken); |
|
|
|
_logger.LogDebug("收到第一条消息,连接ID:{ConnectionId},消息类型:{MessageType}", |
|
|
|
connectionId, receiveResult.MessageType); |
|
|
|
|
|
|
|
// 循环处理消息,直到收到关闭消息或发生错误
|
|
|
|
while (!receiveResult.CloseStatus.HasValue) |
|
|
|
// 为每个连接创建独立的消息缓冲区
|
|
|
|
using var messageBuffer = new WebSocketMessageBuffer(_options.MaxMessageSize); |
|
|
|
var lastMessageTime = DateTime.UtcNow; |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
// 检查消息是否超时
|
|
|
|
if (IsMessageTimeout(messageStartTime)) |
|
|
|
{ |
|
|
|
_logger.LogWarning("消息处理超时,连接ID:{ConnectionId},已处理时间:{ElapsedTime}ms", |
|
|
|
connectionId, (DateTime.UtcNow - messageStartTime).TotalMilliseconds); |
|
|
|
await HandleMessageTimeout(webSocket, connectionId, cancellationToken); |
|
|
|
return; |
|
|
|
} |
|
|
|
// 接收第一条消息
|
|
|
|
var receiveResult = await webSocket.ReceiveAsync( |
|
|
|
new ArraySegment<byte>(buffer), cancellationToken); |
|
|
|
_logger.LogDebug("收到第一条消息,连接ID:{ConnectionId},消息类型:{MessageType}", |
|
|
|
connectionId, receiveResult.MessageType); |
|
|
|
|
|
|
|
// 处理关闭消息
|
|
|
|
if (receiveResult.MessageType == WebSocketMessageType.Close) |
|
|
|
// 循环处理消息,直到收到关闭消息或发生错误
|
|
|
|
while (!receiveResult.CloseStatus.HasValue) |
|
|
|
{ |
|
|
|
_logger.LogInformation("收到关闭消息,连接ID:{ConnectionId},关闭状态:{CloseStatus}", |
|
|
|
connectionId, receiveResult.CloseStatus); |
|
|
|
await HandleCloseMessage(webSocket, receiveResult, cancellationToken); |
|
|
|
break; |
|
|
|
} |
|
|
|
// 检查连接状态
|
|
|
|
if (webSocket.State != WebSocketState.Open) |
|
|
|
{ |
|
|
|
_logger.LogWarning("WebSocket 连接状态异常,连接ID:{ConnectionId},状态:{State}", |
|
|
|
connectionId, webSocket.State); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// 处理有效消息类型(文本或二进制)
|
|
|
|
if (IsValidMessageType(receiveResult.MessageType)) |
|
|
|
{ |
|
|
|
_logger.LogDebug("处理消息,连接ID:{ConnectionId},消息类型:{MessageType},消息大小:{MessageSize}字节", |
|
|
|
connectionId, receiveResult.MessageType, receiveResult.Count); |
|
|
|
await ProcessMessage(webSocket, connectionId, buffer, receiveResult, |
|
|
|
messageChannel, messageStartTime, cancellationToken); |
|
|
|
messageStartTime = DateTime.UtcNow; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning("收到无效消息类型,连接ID:{ConnectionId},消息类型:{MessageType}", |
|
|
|
// 检查消息是否超时(基于最后接收消息的时间)
|
|
|
|
if (IsMessageTimeout(lastMessageTime)) |
|
|
|
{ |
|
|
|
_logger.LogWarning("消息处理超时,连接ID:{ConnectionId},已处理时间:{ElapsedTime}ms", |
|
|
|
connectionId, (DateTime.UtcNow - lastMessageTime).TotalMilliseconds); |
|
|
|
await HandleMessageTimeout(webSocket, connectionId, cancellationToken); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 处理关闭消息
|
|
|
|
if (receiveResult.MessageType == WebSocketMessageType.Close) |
|
|
|
{ |
|
|
|
_logger.LogInformation("收到关闭消息,连接ID:{ConnectionId},关闭状态:{CloseStatus}", |
|
|
|
connectionId, receiveResult.CloseStatus); |
|
|
|
await HandleCloseMessage(webSocket, receiveResult, cancellationToken); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// 处理有效消息类型(文本或二进制)
|
|
|
|
if (IsValidMessageType(receiveResult.MessageType)) |
|
|
|
{ |
|
|
|
_logger.LogDebug("处理消息,连接ID:{ConnectionId},消息类型:{MessageType},消息大小:{MessageSize}字节", |
|
|
|
connectionId, receiveResult.MessageType, receiveResult.Count); |
|
|
|
await ProcessMessage(webSocket, connectionId, buffer, receiveResult, |
|
|
|
messageChannel, messageBuffer, cancellationToken); |
|
|
|
lastMessageTime = DateTime.UtcNow; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning("收到无效消息类型,连接ID:{ConnectionId},消息类型:{MessageType}", |
|
|
|
connectionId, receiveResult.MessageType); |
|
|
|
} |
|
|
|
|
|
|
|
// 接收下一条消息
|
|
|
|
receiveResult = await webSocket.ReceiveAsync( |
|
|
|
new ArraySegment<byte>(buffer), cancellationToken); |
|
|
|
_logger.LogDebug("接收下一条消息,连接ID:{ConnectionId},消息类型:{MessageType}", |
|
|
|
connectionId, receiveResult.MessageType); |
|
|
|
} |
|
|
|
|
|
|
|
// 接收下一条消息
|
|
|
|
receiveResult = await webSocket.ReceiveAsync( |
|
|
|
new ArraySegment<byte>(buffer), cancellationToken); |
|
|
|
_logger.LogDebug("接收下一条消息,连接ID:{ConnectionId},消息类型:{MessageType}", |
|
|
|
connectionId, receiveResult.MessageType); |
|
|
|
_logger.LogInformation("WebSocket 消息处理完成,连接ID:{ConnectionId}", connectionId); |
|
|
|
} |
|
|
|
catch (OperationCanceledException) |
|
|
|
{ |
|
|
|
_logger.LogInformation("WebSocket 消息处理已取消,连接ID:{ConnectionId}", connectionId); |
|
|
|
} |
|
|
|
catch (WebSocketException ex) |
|
|
|
{ |
|
|
|
_logger.LogError(ex, "WebSocket 消息处理发生 WebSocket 异常,连接ID:{ConnectionId},错误:{Error}", |
|
|
|
connectionId, ex.Message); |
|
|
|
throw; |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
_logger.LogError(ex, "WebSocket 消息处理发生未知异常,连接ID:{ConnectionId},错误:{Error}", |
|
|
|
connectionId, ex.Message); |
|
|
|
throw; |
|
|
|
} |
|
|
|
|
|
|
|
_logger.LogInformation("WebSocket 消息处理完成,连接ID:{ConnectionId}", connectionId); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
@ -368,7 +399,7 @@ public class WebSocketMiddleware |
|
|
|
/// <param name="buffer">接收缓冲区</param>
|
|
|
|
/// <param name="receiveResult">接收结果</param>
|
|
|
|
/// <param name="messageChannel">消息通道</param>
|
|
|
|
/// <param name="messageStartTime">消息开始时间</param>
|
|
|
|
/// <param name="messageBuffer">消息缓冲区</param>
|
|
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
|
|
/// <remarks>
|
|
|
|
/// 该方法负责:
|
|
|
@ -383,41 +414,66 @@ public class WebSocketMiddleware |
|
|
|
byte[] buffer, |
|
|
|
WebSocketReceiveResult receiveResult, |
|
|
|
Channel<WebSocketMessage> messageChannel, |
|
|
|
DateTime messageStartTime, |
|
|
|
WebSocketMessageBuffer messageBuffer, |
|
|
|
CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
var processingStartTime = DateTime.UtcNow; |
|
|
|
|
|
|
|
var success = await _errorHandler.HandleWithRetryAsync(async () => |
|
|
|
{ |
|
|
|
if (!_messageBuffer.TryWrite(buffer, 0, receiveResult.Count)) |
|
|
|
// 检查缓冲区是否已满
|
|
|
|
if (!messageBuffer.TryWrite(buffer, 0, receiveResult.Count)) |
|
|
|
{ |
|
|
|
_logger.LogWarning("消息缓冲区已满,连接ID:{ConnectionId},缓冲区大小:{BufferSize},消息大小:{MessageSize}", |
|
|
|
connectionId, messageBuffer.Size, receiveResult.Count); |
|
|
|
throw new WebSocketException("消息缓冲区溢出"); |
|
|
|
} |
|
|
|
|
|
|
|
// 检查消息是否完整
|
|
|
|
if (receiveResult.EndOfMessage) |
|
|
|
{ |
|
|
|
var messageData = messageBuffer.GetMessage(); |
|
|
|
|
|
|
|
// 检查消息大小是否超过限制
|
|
|
|
if (messageData.Length > _options.MaxMessageSize) |
|
|
|
{ |
|
|
|
_logger.LogWarning("消息大小超过限制,连接ID:{ConnectionId},消息大小:{MessageSize},限制:{MaxSize}", |
|
|
|
connectionId, messageData.Length, _options.MaxMessageSize); |
|
|
|
throw new WebSocketException("消息大小超过限制"); |
|
|
|
} |
|
|
|
|
|
|
|
var message = new WebSocketMessage |
|
|
|
{ |
|
|
|
ConnectionId = connectionId, |
|
|
|
Data = _messageBuffer.GetMessage(), |
|
|
|
Data = messageData, |
|
|
|
MessageType = receiveResult.MessageType, |
|
|
|
IsComplete = true |
|
|
|
IsComplete = true, |
|
|
|
Timestamp = DateTime.UtcNow |
|
|
|
}; |
|
|
|
|
|
|
|
await messageChannel.Writer.WriteAsync(message, cancellationToken); |
|
|
|
// 检查通道是否已关闭
|
|
|
|
if (messageChannel.Writer.TryWrite(message)) |
|
|
|
{ |
|
|
|
var processingTime = (DateTime.UtcNow - processingStartTime).TotalMilliseconds; |
|
|
|
_performanceMonitor.RecordMessage( |
|
|
|
connectionId, |
|
|
|
message.Data.Length, |
|
|
|
(long)processingTime); |
|
|
|
|
|
|
|
var processingTime = (DateTime.UtcNow - processingStartTime).TotalMilliseconds; |
|
|
|
_performanceMonitor.RecordMessage( |
|
|
|
connectionId, |
|
|
|
message.Data.Length, |
|
|
|
(long)processingTime); |
|
|
|
// 记录 Channel 消息处理统计
|
|
|
|
_channelManager.RecordMessageProcessed(messageChannel, message.Data.Length); |
|
|
|
|
|
|
|
// 记录 Channel 消息处理统计
|
|
|
|
_channelManager.RecordMessageProcessed(messageChannel, message.Data.Length); |
|
|
|
_logger.LogDebug("消息已成功写入通道,连接ID:{ConnectionId},消息大小:{MessageSize}字节", |
|
|
|
connectionId, message.Data.Length); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning("消息通道已关闭,无法写入消息,连接ID:{ConnectionId}", connectionId); |
|
|
|
throw new InvalidOperationException("消息通道已关闭"); |
|
|
|
} |
|
|
|
|
|
|
|
_messageBuffer.Reset(); |
|
|
|
//messageStartTime = DateTime.UtcNow;
|
|
|
|
// 重置缓冲区
|
|
|
|
messageBuffer.Reset(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|