SignalR 协议深度分析

1. 握手协议 (Negotiation)

1.1 客户端发起握手

POST /chathub/negotiate HTTP/1.1
Host: localhost:5000
Content-Type: application/json
Connection: keep-alive

{
  "protocol": "json",
  "version": 1
}

1.2 服务器响应

HTTP/1.1 200 OK
Content-Type: application/json

{
  "connectionId": "abc123",
  "availableTransports": [
    {
      "transport": "WebSockets",
      "transferFormats": ["Text", "Binary"]
    },
    {
      "transport": "ServerSentEvents",
      "transferFormats": ["Text"]
    },
    {
      "transport": "LongPolling",
      "transferFormats": ["Text", "Binary"]
    }
  ]
}

2. WebSocket 消息格式

2.1 消息类型枚举

public enum MessageType
{
    Invocation = 1,        // 方法调用
    StreamItem = 2,        // 流数据项
    Completion = 3,       // 完成
    StreamInvocation = 4,  // 流调用
    CancelInvocation = 5,  // 取消调用
    Ping = 6,             // 心跳
    Pong = 7,             // 心跳响应
    Close = 8,             // 关闭连接
    Ack = 9                // 确认
}

2.2 实际消息示例

客户端调用服务器方法
{
  "protocol": "json",
  "version": 1,
  "type": 1,  // Invocation
  "target": "SendMessage",
  "arguments": ["张三", "你好世界"],
  "invocationId": "12345"
}
服务器调用客户端方法
{
  "protocol": "json",
  "version": 1,
  "type": 1,  // Invocation
  "target": "ReceiveMessage",
  "arguments": ["张三", "你好世界"]
}
心跳消息
{
  "protocol": "json",
  "version": 1,
  "type": 6  // Ping
}

3. 长轮询协议

3.1 轮询请求

POST /chathub/poll?connectionId=abc123 HTTP/1.1
Host: localhost:5000
Content-Type: application/json
Connection: keep-alive

{
  "protocol": "json",
  "version": 1
}

3.2 轮询响应

HTTP/1.1 200 OK
Content-Type: application/json
Connection: keep-alive

{
  "messages": [
    {
      "protocol": "json",
      "version": 1,
      "type": 1,
      "target": "ReceiveMessage",
      "arguments": ["张三", "你好世界"]
    }
  ]
}

4. 二进制协议 (MessagePack)

4.1 消息结构

[消息类型][消息长度][消息内容]

4.2 序列化示例

// C# 对象
var message = new { User = "张三", Content = "你好" };

// MessagePack 序列化后的字节数组
[0x01, 0x00, 0x00, 0x00, 0x1A, 0x82, 0xA4, 0x55, 0x73, 0x65, 0x72, 0xA6, 0xE5, 0xBC, 0xA0, 0xE4, 0xB8, 0x89, 0xA7, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0xA6, 0xE4, 0xBD, 0xA0, 0xE5, 0xA5, 0xBD]

5. 连接管理

5.1 连接状态

public enum ConnectionState
{
    Disconnected = 0,
    Connecting = 1,
    Connected = 2,
    Reconnecting = 3
}

5.2 连接生命周期

1. 创建连接对象
2. 发起握手请求
3. 选择传输协议
4. 建立连接通道
5. 开始消息交换
6. 处理断开/重连

6. 错误处理

6.1 错误消息格式

{
  "protocol": "json",
  "version": 1,
  "type": 3,  // Completion
  "invocationId": "12345",
  "error": "方法 'SendMessage' 不存在",
  "result": null
}

6.2 常见错误类型

  • 连接错误: 网络中断、服务器不可用
  • 协议错误: 消息格式不正确
  • 方法错误: 调用的方法不存在
  • 参数错误: 参数类型不匹配
  • 授权错误: 没有权限访问方法

7. 性能优化

7.1 消息批处理

{
  "protocol": "json",
  "version": 1,
  "type": 1,
  "target": "ReceiveMessage",
  "arguments": [
    ["用户1", "消息1"],
    ["用户2", "消息2"],
    ["用户3", "消息3"]
  ]
}

7.2 压缩传输

// 启用 GZIP 压缩
services.AddSignalR()
    .AddHubOptions<ChatHub>(options =>
    {
        options.EnableDetailedErrors = true;
        options.MaximumReceiveMessageSize = 32 * 1024;
    });

8. 安全机制

8.1 身份验证

[Authorize]
public class ChatHub : Hub
{
    public async Task SendMessage(string message)
    {
        var user = Context.User.Identity.Name;
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

8.2 授权策略

[Authorize(Policy = "ChatPolicy")]
public class ChatHub : Hub
{
    // 只有通过授权策略的用户才能访问
}

9. 调试技巧

9.1 启用详细日志

services.AddSignalR()
    .AddHubOptions<ChatHub>(options =>
    {
        options.EnableDetailedErrors = true;
    });

9.2 客户端调试

// 启用详细日志
const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Debug)
    .build();

10. 实际应用场景

10.1 聊天应用

  • 实时消息传递
  • 用户状态同步
  • 群组管理

10.2 游戏服务器

  • 实时游戏状态同步
  • 玩家动作广播
  • 游戏事件通知

10.3 IoT 设备

  • 设备状态监控
  • 远程控制指令
  • 数据采集

总结

SignalR 的底层原理可以概括为:

  1. 协议层: WebSocket + 长轮询 + Server-Sent Events
  2. 消息层: JSON/MessagePack 序列化
  3. RPC层: 双向方法调用机制
  4. 传输层: HTTP/WebSocket 协议
  5. 安全层: 身份验证 + 授权策略

这就是为什么 JavaScript 能调用 C# 方法,C# 能调用 JavaScript 函数的根本原理!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

helloworddm

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值