概述:互联网的发展使即时通信技术比以往任何时候都更加重要,尤其是对于物联网 (IoT)。由于智能家居设备和工业传感器等众多设备需要顺利地相互通信,因此快速可靠的通信至关重要。这就是 WebSockets 的用武之地。它们非常适合在物联网设备和服务器之间进行快速的双向聊天,帮助一切保持实时连接和最新状态。什么是 SignalR?SignalR 现在是 ASP.NET Core Framework 的一部分,是使用 .net 创建实时应用程序的事实标准。SignalR 是 ASP.NET Core 套件中的高级框架,旨在生成实时 Web 应用程序。它使用自定义协议抽象了实时通信的复杂性,使开发人员能够更
互联网的发展使即时通信技术比以往任何时候都更加重要,尤其是对于物联网 (IoT)。由于智能家居设备和工业传感器等众多设备需要顺利地相互通信,因此快速可靠的通信至关重要。这就是 WebSockets 的用武之地。它们非常适合在物联网设备和服务器之间进行快速的双向聊天,帮助一切保持实时连接和最新状态。
什么是 SignalR?
SignalR 现在是 ASP.NET Core Framework 的一部分,是使用 .net 创建实时应用程序的事实标准。
SignalR 是 ASP.NET Core 套件中的高级框架,旨在生成实时 Web 应用程序。它使用自定义协议抽象了实时通信的复杂性,使开发人员能够更多地关注应用程序逻辑而不是底层协议。SignalR 的一个关键优势是它支持客户端和服务器之间通信的多种传输,确保应用程序可以在不同环境中保持实时功能。这些运输包括:
-
WebSockets,用于全双工通信,非常适合需要高频数据交换的场景。
-
服务器发送事件 (SSE),允许服务器在单向通信充分的情况下将更新推送到客户端。
-
长轮询,一种回退机制,当客户端或服务器环境不支持更高级的通信方法时,可以使用该机制。
通过自动选择最佳可用传输方法,SignalR 可确保在各种设备和网络条件下为 Web 应用程序提供最佳功能和性能。
SignalR 是用于开发实时 Web 应用程序的绝佳框架。但是,它对特定协议和客户端兼容性的依赖可能会引入限制,尤其是在需要直接 WebSocket 通信的情况下。
简单
进入 SimpleR,这是一个基于 ASP.NET Core 的高性能、低开销、纯 WebSocket 服务器库。SimpleR 旨在弥合 SignalR 可能不是最佳选择的差距,它在简单性和灵活性方面大放异彩。它删除了繁重的协议和抽象,转而提供一种简单、高效的方法来实现纯 WebSocket 服务器。这使得它成为需要直接控制 WebSocket 通信、自定义协议实现或使用非 SignalR 客户端(例如,使用具有自己的自定义协议的 IoT 设备时)的项目的理想候选者。
在对 SimpleR 的介绍中,我们将探讨其主要功能,并演示如何与 ASP.NET Core 无缝集成,以实现轻量级高性能 WebSocket 服务器的开发。
设计理念
SimpleR 主要基于 SignalR 构建,建立在 ASP.NET Core 团队所做的出色工作之上。它旨在提供
-
通过网络传输实现高性能、低分配抽象,同时与所有 ASP.NET Core 功能完全集成。
-
性能和最少的分配优先于易用性。
-
与协议无关的方法。
设置环境
在深入了解使用 SimpleR 的细节之前,您需要从基础知识开始——创建一个空的 ASP.NET Core Web 应用程序。这为设置 WebSocket 服务器提供了一个全新的石板。
-
**打开命令行界面 (CLI):**导航到要创建项目的文件夹。
-
创建新的 Web 项目:运行以下命令以生成空的 ASP.NET Core Web 应用程序
dotnet new web -n SimpleThermostat.Server
3. **导航到项目文件夹:**将目录更改为新创建的项目文件夹
cd SimpleThermostat.Server
4. 安装 SimpleR.Server 包:在项目目录下,运行以下命令,将 SimpleR.Server 包添加到项目中。在撰写本文时,SimpleR 仍处于 alpha 阶段。
dotnet add package SimpleR.Server --version 1.0.0-alpha.1
定义协议
让我们从定义客户端和服务器消息开始。为了允许不同类型的消息,我们将使用 System.Text.Json 多态序列化功能。
客户端(在本例中为恒温器)将向服务器发送指标。
[JsonDerivedType(typeof(ThermostatTemperatureMetric), "temperature")]
public class ThermostatMetric;
public class ThermostatTemperatureMetric : ThermostatMetric
{
public ThermostatTemperatureMetric(float temperature)
{
Temperature = temperature;
}
public float Temperature { get; }
}
另一方面,服务器将向恒温器发送命令。
[JsonDerivedType(typeof(SetThermostatModeCommand), "setMode")]
public class ThermostatCommand;
public class SetThermostatModeCommand : ThermostatCommand
{
public SetThermostatModeCommand(ThermostatMode mode)
{
Mode = mode;
}
public ThermostatMode Mode { get; }
}
public enum ThermostatMode
{
Off,
Heat,
Cool
}
现在我们已经拥有了协议支持的所有消息,让我们定义如何将它们转换为字节,反之亦然。
SimpleR 的关键点之一是它与协议无关。这意味着它要求用户提供协议定义,以便能够从字节流中构造消息。
在这个演示中,我们不会深入定义我们自己的自定义协议,而是使用 WebSocket 的 EndOfMessage 作为消息的分隔符。
为此,我们需要定义一对读取器和编写器类。
// Since we are using WebSocket's EndOfMessage as a delimiter,
// need to implement the IDelimitedMessageReader interface
public class ThermostatMessageReader : IDelimitedMessageReader<ThermostatMetric>
{
public ThermostatMetric ParseMessage(ref ReadOnlySequence<byte> input)
{
var jsonReader = new Utf8JsonReader(input);
return JsonSerializer.Deserialize<ThermostatMetric>(ref jsonReader)!;
}
}public class ThermostatMessageWriter : IMessageWriter<ThermostatCommand>
{
public void WriteMessage(ThermostatCommand message, IBufferWriter<byte> output)
{
var jsonWriter = new Utf8JsonWriter(output);
JsonSerializer.Serialize(jsonWriter, message);
}
}
现在我们已经成功定义了自己的消息协议,我们准备继续讨论应用程序逻辑。
调度消息
SimpleR 中的下一个重要主题是消息调度程序。简而言之,消息调度器是一个高级管道,它封装了调度连接消息的逻辑。这是我们应用程序逻辑的初始入口。
public class ThermostatMessageDispatcher : IWebSocketMessageDispatcher<ThermostatMetric, ThermostatCommand>
{
private float _targetTemp = 22;
public Task OnConnectedAsync(IWebsocketConnectionContext<ThermostatCommand> connection)
{
return Task.CompletedTask;
}
public Task OnDisconnectedAsync(IWebsocketConnectionContext<ThermostatCommand> connection, Exception? exception)
{
return Task.CompletedTask;
}
public async Task DispatchMessageAsync(IWebsocketConnectionContext<ThermostatCommand> connection, ThermostatMetric message)
{
if(message is ThermostatTemperatureMetric temperatureMetric)
{
// update temperature
if (temperatureMetric.Temperature < _targetTemp)
{
// If the temperature is below the target temperature, set the thermostat to heat mode
await connection.WriteAsync(new SetThermostatModeCommand(ThermostatMode.Heat));
}
else if (temperatureMetric.Temperature > _targetTemp)
{
// If the temperature is above the target temperature, set the thermostat to cool mode
await connection.WriteAsync(new SetThermostatModeCommand(ThermostatMode.Cool));
}
else
{
// If the temperature is at the target temperature, turn off the thermostat
await connection.WriteAsync(new SetThermostatModeCommand(ThermostatMode.Off));
}
}
}
}
将一切连接在一起
定义消息协议和消息调度程序后,我们就可以在 Program.cs 文件中将其连接在一起。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSimpleR();
var app = builder.Build();
app.MapSimpleR<ThermostatMetric, ThermostatCommand>("thermostat/{deviceId}", b =>
{
b.UseDispatcher<ThermostatMessageDispatcher>()
.UseEndOfMessageDelimitedProtocol(
MessageProtocol.From(new ThermostatMessageReader(), new ThermostatMessageWriter()));
});
app.Run();
就这么简单!
您可以在此处找到服务器的源代码以及一个简单的客户端。
要探索 SimpleR 的所有功能,请查看 Github 存储库中的文档。如果您发现它有用,请不要忘记为存储库加星标。
当我们结束对 SimpleR 的研究时,很明显,对于那些需要直接控制 ASP.NET Core 中的 WebSocket 通信的人来说,这个库是一个不错的选择。展望未来,我们有令人兴奋的计划来使 SimpleR 变得更好。我们将添加现成的协议,使构建应用程序更容易,并包括用于广泛使用的标准(如 OCPP)的特殊软件包。