
SignalR 是.NET Core 的实现实时通讯的开源框架,抽象于长轮询、SSE 和 WS 这三种技术之上。用于实时的 web 应用。
前言
这是学习 ASP.NET Core 的笔记,主要是根据微软 MVP 杨旭的课程来走的,当然也有自己的偏向。关于这些内容的笔记和代码以及更多的简介在Github上。
SignalR 是.NET Core 的实现实时通讯的开源框架,抽象于长轮询、SSE 和 WS 这三种技术之上。用于实时的 web 应用。
这一篇主要是SignalR的介绍和 ASP.NET Core 项目使用SignalR等内容。
SignalR
SignalR 是.NET Core 的开源实时框架,抽象与三种技术(见下)之上。无论使用哪种技术,使用 SignalR 是没有感觉到区别的。
用于实时的 web 应用。
传统的是浏览器发送请求、服务器处理请求、返回 payload;实时的 web 应用由 web 服务器主动通知客户端数据有变化。
技术
SignalR 使用了三种“底层”的技术来实现实时 Web。分别是:
- Long Polling: 长轮询;
- Server Sent Event;
- Websocket.
Signal 采用了回落机制,有限使用 WS,如果浏览器不支持再降级为 SSE 和 Long Polling。
轮询
Polling 是定期向服务器发送请求,有变化则更改数据,很简单,但是浪费资源。
长轮询:与轮询的不同之处是如果服务器上面的数据没有更改,则保持连接(不会立即返回 HTTP 204
并断开),直到超时。超时后再次亲求。
Server Sent Events (SSE)
使用 SSE,web 服务器可以在任何时间发送数据。而客户端(浏览器)会一直监听进来的信息,这个连接也会一直开放,直到服务器主动关闭。
浏览器会使用一个叫做 EventSource 的对象来处理传过来的信息。
优点:使用简单,HTTP 协议。
缺点:浏览器有最大并发、只能发送文本,只能单项通讯。
WebSocket
WS 是不同于 HTTP 的另一个 TCP 协议。
优点
- 使用 WS 消息可以双向发送(全双工);
- 没有 HTTP 的延迟,信息流没有完成的时候 TCP 端口始终打开;
- 大部分情况下(现代浏览器) SignalR 会使用 WS 协议,这也是最有效的传输方式;
- WS 可以传输文本或者二进制文件;
- WS 不受 SSE 连接数限制,大部分浏览器对 WS 连接支持数为 50 个。
生命周期
- 发送一个 HTTP 请求到服务器进行握手;
- 通讯;
- 关闭(会返回关闭原因)。
HTTP 握手
- 每一个 WS 开始的时候都是一个简单的 HTTP Socket;
- 客户端发送 GET 请求升级 Socket(HTTP 101);
- 服务器同意的话(HTTP 101),升级为 WebSocket。
消息类型
消息类型可以是文本或二进制。
每个消息由一个或多个 Frame 组成。
RPC
RPC 的优点是可以像调用本地方法一样调用远程服务。
SignalR 采用了 RPC 范式来进行通讯。服务端和客户端可以相互调用彼此的方法。SignalR 负责序列化和反序列化。
Hub
Hub 是 SignalR 的一个组件,是服务端的一个类。
在 ASP.NET Core 中自己创建的 Hub 类需要继承与基类 Hub。
在 Hub 类里面可以调用客户端上面的方法,客户端也可以调用 Hub 类里面的方法。
Hub 可以序列化和反序列化,被序列化的参数的格式叫做 Hub 协议。Hub 的默认协议是 JSON,也支持 MessagePack(二进制的,更紧凑更快速)。
横向扩展
负载均衡器会保证每个进来的请求按照一定的逻辑分配。但是长轮询时候请求发送到不同的服务器就很容易出问题。
实践
配置项目
在 StartUp
中注册服务:
1 | public void ConfigureServices(IServiceCollection services) |
自定义一个测试用的类(这里写个技术调用的)
1 | public class CountService |
注册服务
1 | services.AddSingleton<CountService>(); |
创建一个 Hub,命名为 CountHub.cs
1 | using Microsoft.AspNetCore.SignalR; |
使用 Hub:配置端点,加入
1 | // 使用Hub,参数为亲求的端点 |
创建一个控制器 CountController
1 | using Microsoft.AspNetCore.Mvc; |
在 Hub 中重写 OnConnectedAsync()
来执行一些方法:
1 | public override async Task OnConnectedAsync() |
常见的操作有:
1 | // 获取ConnectId |
使用 Hub 身份认证,需要加入 [Authorize]
属性
可以使用
1 | var userName = Context.User.Identity.Name; |
获取认证的用户名。其它属性也类似。
至于 SignalR,我会以后有时间来研究一下。
客户端
使用 libman 安装 SignalR@next
JavaScript
1 | let connection = null; |