Browse Source

回退

feature/x1-web-request
root 1 week ago
parent
commit
39a6e5c3cf
  1. 388
      src/modify.md

388
src/modify.md

@ -52,4 +52,390 @@
- 使用 JsonSerializerOptions 配置大小写不敏感和驼峰命名
- 添加了消息数量统计和错误计数
- 改进了异常处理的分层结构
- 优化了日志输出的格式和内容
- 优化了日志输出的格式和内容
## 2024-12-19 WebSocketMiddleware ProcessWebSocketMessages 修复
### 修改文件
- `X1.WebSocket/Middleware/WebSocketMiddleware.cs`
### 主要问题修复
#### 1. 消息缓冲区共享问题
- **问题**:`_messageBuffer` 是类的成员变量,被所有连接共享,导致数据混乱
- **修复**:为每个连接创建独立的 `WebSocketMessageBuffer` 实例
- **影响**:避免多连接间的数据干扰,提高并发安全性
#### 2. 消息超时逻辑错误
- **问题**:`messageStartTime` 在循环中被重置,超时检查逻辑有问题
- **修复**:基于最后接收消息的时间进行超时检查
- **影响**:确保超时机制正确工作,及时检测到超时连接
#### 3. 缓冲区重置时机不当
- **问题**:只有在 `EndOfMessage` 为 true 时才重置缓冲区
- **修复**:在消息完整处理后立即重置缓冲区
- **影响**:避免缓冲区累积过多数据,提高内存使用效率
#### 4. 异常处理不完善
- **问题**:缺少对 WebSocket 连接状态的检查,没有处理连接意外断开的情况
- **修复**:添加连接状态检查和详细的异常处理机制
- **影响**:提高系统稳定性,避免因连接异常导致的崩溃
#### 5. 资源泄漏风险
- **问题**:缓冲区没有正确释放,异常情况下可能导致资源泄漏
- **修复**:使用 `using` 语句确保缓冲区正确释放
- **影响**:防止内存泄漏,提高资源管理效率
### 技术改进
#### 1. 连接状态验证
- 在处理消息前检查 WebSocket 连接状态
- 及时发现并处理异常连接状态
#### 2. 消息大小验证
- 在处理消息前验证消息大小是否超过限制
- 防止过大消息导致的内存问题
#### 3. 通道状态检查
- 在写入消息前检查通道是否已关闭
- 避免向已关闭的通道写入数据
#### 4. 增强的日志记录
- 添加更详细的调试和错误日志
- 便于问题排查和性能监控
#### 5. 资源管理优化
- 使用 `using` 语句自动管理缓冲区生命周期
- 确保异常情况下资源也能正确释放
### 性能影响
- 提高并发处理能力,避免连接间的数据竞争
- 减少内存泄漏风险,提高系统稳定性
- 优化超时检测机制,及时释放无效连接
- 改进异常处理,减少系统崩溃概率
## 2024-12-19 WebSocket 缓冲区管理问题修复
### 修改文件
- `X1.WebSocket/Middleware/WebSocketMiddleware.cs`
### 问题描述
从日志中发现缓冲区溢出错误:
```
[17:19:07 WRN] 消息缓冲区已满,连接ID:ff70aebb-c0a2-40a3-b478-8aaa00daf50f,缓冲区大小:1048576,消息大小:4096
[17:19:07 WRN] 操作失败,重试 1/3
System.Net.WebSockets.WebSocketException (0x80004005): 消息缓冲区溢出
```
### 根本原因分析
#### 1. 缓冲区大小设置错误
- **问题**:缓冲区大小设置为 `_options.MaxMessageSize`(1MB),但这是用来累积分片消息的
- **影响**:当消息分片传输时,缓冲区会累积所有分片直到达到最大大小,导致溢出
#### 2. 分片消息处理逻辑缺失
- **问题**:没有正确处理大型消息的分片传输
- **影响**:分片消息无法正确累积和重组
#### 3. 缓冲区管理逻辑错误
- **问题**:在写入数据前没有检查总大小是否会超过限制
- **影响**:可能导致缓冲区溢出
### 修复方案
#### 1. 优化缓冲区大小设置
- **修复**:将缓冲区大小设置为 `MaxMessageSize` 的 1.5 倍
- **原因**:确保有足够空间处理分片消息,避免溢出
- **代码**
```csharp
var bufferSize = (int)(_options.MaxMessageSize * 1.5);
using var messageBuffer = new WebSocketMessageBuffer(bufferSize);
```
#### 2. 改进缓冲区写入逻辑
- **修复**:在写入前检查总大小是否会超过限制
- **原因**:提前检测溢出风险,避免不必要的写入操作
- **代码**
```csharp
var totalSize = messageBuffer.Size + receiveResult.Count;
if (totalSize > _options.MaxMessageSize)
{
throw new WebSocketException("消息大小超过限制");
}
```
#### 3. 增强分片消息处理
- **修复**:添加分片消息的详细日志记录
- **原因**:便于调试和监控分片消息的处理过程
- **代码**
```csharp
_logger.LogDebug("消息分片已累积,连接ID:{ConnectionId},当前缓冲区大小:{BufferSize}字节",
connectionId, messageBuffer.Size);
```
#### 4. 改进错误处理和日志
- **修复**:提供更详细的错误信息和调试日志
- **原因**:便于问题排查和性能监控
- **改进**
- 区分"消息大小超过限制"和"缓冲区写入失败"
- 添加缓冲区状态和分片处理过程的详细日志
- 在关键操作点添加调试日志
### 技术细节
#### 1. 缓冲区大小计算
- 原始大小:`_options.MaxMessageSize`(1MB)
- 新大小:`_options.MaxMessageSize * 1.5`(1.5MB)
- 原因:为分片消息提供足够的缓冲空间
#### 2. 大小检查策略
- 写入前检查:`totalSize = currentSize + newDataSize`
- 最终验证:`messageData.Length > _options.MaxMessageSize`
- 双重保护:确保消息大小在合理范围内
#### 3. 分片处理流程
- 累积分片:`messageBuffer.TryWrite(buffer, 0, receiveResult.Count)`
- 检查完整性:`receiveResult.EndOfMessage`
- 重组消息:`messageBuffer.GetMessage()`
- 重置缓冲区:`messageBuffer.Reset()`
### 性能影响
- **内存使用**:缓冲区大小增加 50%,但避免了溢出错误
- **处理效率**:提前检测大小限制,避免无效的写入操作
- **稳定性**:正确处理分片消息,提高系统稳定性
- **可维护性**:详细的日志记录,便于问题排查
### 测试建议
1. 测试大型消息的分片传输
2. 验证缓冲区大小限制的正确性
3. 检查分片消息的完整重组
4. 监控内存使用情况
5. 验证错误处理的正确性
## 2024-12-19 WebSocket 错误处理优化
### 修改文件
- `X1.WebSocket/Middleware/WebSocketMiddleware.cs`
### 问题描述
从日志中发现重试机制在缓冲区满的情况下无效:
```
[17:19:07 WRN] 消息缓冲区已满,连接ID:ff70aebb-c0a2-40a3-b478-8aaa00daf50f,缓冲区大小:1048576,消息大小:4096
[17:19:07 WRN] 操作失败,重试 1/3
[17:19:08 WRN] 操作失败,重试 2/3
[17:19:09 WRN] 操作失败,重试 3/3
[17:19:09 ERR] 消息处理失败,连接ID:ff70aebb-c0a2-40a3-b478-8aaa00daf50f,关闭连接
```
### 根本原因分析
#### 1. 重试机制设计缺陷
- **问题**:对于缓冲区满等状态性问题,重试机制没有意义
- **影响**:浪费系统资源,延迟错误处理
#### 2. 异常类型区分不足
- **问题**:没有区分不同类型的异常,所有异常都进行重试
- **影响**:对不可恢复的错误进行无效重试
#### 3. 资源清理不完整
- **问题**:存在未使用的成员变量 `_messageBuffer`
- **影响**:代码冗余,可能造成混淆
### 修复方案
#### 1. 优化异常处理策略
- **修复**:区分 WebSocket 异常和其他异常
- **原因**:WebSocket 异常通常不可恢复,不需要重试
- **代码**
```csharp
catch (WebSocketException ex)
{
// 对于 WebSocket 异常,直接抛出,不进行重试
_logger.LogError(ex, "WebSocket 消息处理异常,连接ID:{ConnectionId},错误:{Error}",
connectionId, ex.Message);
throw;
}
catch (Exception ex)
{
// 对于其他异常,使用重试机制
// ...
}
```
#### 2. 移除未使用的成员变量
- **修复**:移除 `_messageBuffer` 成员变量和初始化代码
- **原因**:清理代码冗余,避免混淆
- **改进**
- 移除成员变量声明:`private readonly WebSocketMessageBuffer _messageBuffer;`
- 移除初始化代码:`_messageBuffer = new WebSocketMessageBuffer(_options.MaxMessageSize);`
#### 3. 改进错误日志记录
- **修复**:提供更详细的错误分类和日志信息
- **原因**:便于问题排查和性能监控
- **改进**
- 区分 WebSocket 异常和其他异常
- 提供更具体的错误描述
- 减少无效的重试日志
### 技术细节
#### 1. 异常分类策略
- **WebSocket 异常**:直接抛出,不重试
- 缓冲区溢出
- 消息大小超限
- 连接状态异常
- **其他异常**:使用重试机制
- 网络临时错误
- 系统资源临时不足
#### 2. 重试逻辑优化
- **适用场景**:临时性、可恢复的错误
- **不适用场景**:状态性、不可恢复的错误
- **重试策略**:指数退避,避免系统过载
#### 3. 资源管理改进
- **成员变量清理**:移除未使用的 `_messageBuffer`
- **内存优化**:减少不必要的对象创建
- **代码简化**:提高代码可读性和维护性
### 性能影响
- **响应速度**:减少无效重试,提高错误响应速度
- **资源使用**:减少系统资源浪费
- **稳定性**:更准确的错误处理,提高系统稳定性
- **可维护性**:代码更清晰,便于维护和调试
### 测试建议
1. 测试缓冲区满时的错误处理
2. 验证不同类型异常的处理策略
3. 检查重试机制的正确性
4. 监控系统资源使用情况
5. 验证错误日志的准确性
## 2024-12-19 HandleWebSocketConnection 缓冲区大小修复
### 修改文件
- `X1.WebSocket/Middleware/WebSocketMiddleware.cs`
### 问题描述
- 原实现中 buffer 大小为 4KB(`1024 * 4`),与 WebSocketOptions.MaxMessageSize(如 1MB)不匹配。
- 当接收大消息时,分片次数多,增加缓冲区溢出和性能问题风险。
### 修复方案
- 将 buffer 大小调整为 `_options.MaxMessageSize`,与最大消息大小保持一致。
- 这样可减少分片次数,提高性能,降低溢出风险。
### 代码片段
```csharp
// 修复前
var buffer = ArrayPool<byte>.Shared.Rent(1024 * 4);
// 修复后
var buffer = ArrayPool<byte>.Shared.Rent(_options.MaxMessageSize);
```
### 影响
- 提高了大消息处理的效率和健壮性。
- 降低了分片累积导致的缓冲区溢出风险。
- 代码更符合最佳实践。
## 2024-12-19 ProcessMessage 检查逻辑优化
### 修改文件
- `X1.WebSocket/Middleware/WebSocketMiddleware.cs`
### 问题描述
- `ProcessMessage` 方法中存在冗余的大小检查逻辑
- 在已经提前检查 `totalSize` 的情况下,后续的检查理论上不应该失败
- 日志级别使用不当,某些错误情况应该使用 Error 级别
### 优化方案
#### 1. 优化检查逻辑
- 保留提前的 `totalSize` 检查作为主要验证
- 将后续检查作为安全验证,并调整日志级别为 Error
- 添加注释说明检查的层次和目的
#### 2. 改进日志记录
- 将不应该发生的错误情况日志级别调整为 Error
- 添加更明确的错误描述,便于问题排查
### 代码改进
```csharp
// 主要检查:提前验证大小
var totalSize = messageBuffer.Size + receiveResult.Count;
if (totalSize > _options.MaxMessageSize)
{
// 正常的大小超限情况,使用 Warning 级别
_logger.LogWarning("消息大小将超过限制...");
}
// 安全验证:理论上不应该失败
if (!messageBuffer.TryWrite(buffer, 0, receiveResult.Count))
{
// 不应该发生的情况,使用 Error 级别
_logger.LogError("消息缓冲区写入失败,这不应该发生");
}
// 最终验证:双重保护
if (messageData.Length > _options.MaxMessageSize)
{
// 不应该发生的情况,使用 Error 级别
_logger.LogError("最终消息大小超过限制,这不应该发生");
}
```
### 影响
- 提高了代码的可读性和维护性
- 更准确的日志级别分类
- 保持了安全检查的完整性
- 便于问题排查和调试
## 2024-12-19 移除无意义的重试逻辑
### 修改文件
- `X1.WebSocket/Middleware/WebSocketMiddleware.cs`
### 问题描述
- `ProcessMessage` 方法中的重试逻辑没有实际意义
- 对于 WebSocketException,已经单独 catch 并直接抛出
- 对于其他异常,重试逻辑只是简单地 `throw ex`,没有实际重试操作
- `HandleMessageProcessingFailure` 只会在所有重试都失败后调用,但由于每次都直接抛出异常,实际上不会有任何重试
### 优化方案
- 移除无意义的重试逻辑
- 简化异常处理流程
- 直接调用 `HandleMessageProcessingFailure`
### 代码改进
```csharp
// 优化前
catch (Exception ex)
{
_logger.LogError(ex, "消息处理发生未知异常,连接ID:{ConnectionId},错误:{Error}",
connectionId, ex.Message);
var success = await _errorHandler.HandleWithRetryAsync(async () =>
{
// 这里可以添加重试逻辑,但对于缓冲区问题,重试通常无效
throw ex; // 重新抛出异常
});
if (!success)
{
await HandleMessageProcessingFailure(webSocket, connectionId, cancellationToken);
}
}
// 优化后
catch (Exception ex)
{
_logger.LogError(ex, "WebSocket 消息处理发生未知异常,连接ID:{ConnectionId},错误:{Error}",
connectionId, ex.Message);
await HandleMessageProcessingFailure(webSocket, connectionId, cancellationToken);
}
```
### 影响
- 简化了代码逻辑,提高了可读性
- 减少了不必要的重试开销
- 保持了错误处理的完整性
- 提高了代码执行效率
Loading…
Cancel
Save