ASP.NET Core WebSockets
Posted
技术标签:
【中文标题】ASP.NET Core WebSockets【英文标题】: 【发布时间】:2019-12-04 01:57:24 【问题描述】:我正在尝试在 ASP.NET Core 上启动并运行 WebSocket 服务器。我创建了一个空的 web 项目 dotnet new web
将 Program.cs
更改为:
public static void Main(string[] args)
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
webBuilder.UseStartup<Startup>();
)
.Build()
.Run();
和Startup.cs
的ConfigureServices
方法:
public void ConfigureServices(IServiceCollection services)
services.AddControllers();
services.AddWebSockets();
和Configure
方法:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseWebSockets();
app.UseRouting();
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
endpoints.MapConnectionHandler<WebSocketHandler>("/ws");
);
我的WebSocketHandler
的OnConnectedAsync
方法如下:
public override async Task OnConnectedAsync(ConnectionContext connection)
var context = connection.GetHttpContext();
var endpoint = $"connection.RemoteEndPoint";
if (!context.WebSockets.IsWebSocketRequest)
connection.Abort();
_logger.LogCritical($"Request from endpoint endpoint aborted.");
return;
var websocket = await context.WebSockets.AcceptWebSocketAsync();
_logger.LogInformation($"WebSocket request from endpoint endpoint accepted!");
当我尝试连接到APP_URL/ws
并且每次服务器在收到请求后立即关闭连接时,就会出现问题。以下是日志:https://pastebin.com/raw/34yu7thw
如果我在OnConnectedAsync
方法的末尾放置一个Task.Delay(-1)
,它会保持连接打开但会丢弃传入的连接。
我搜索了 MSDocs,但找不到太多关于如何使用 MapConnectionHandler<T>
的文档。
有一个while循环来接收来自OnConnectedAsync
中多个客户端的消息对我来说安全吗?
这不是处理 websocket 连接的正确方法吗?
MapConnectionHandler<T>
是瞬态的吗?
我真的很困惑,无法弄清楚它的行为。
【问题讨论】:
这可能是你的问题。 "docs.microsoft.com/en-us/aspnet/core/fundamentals/…" 使用 WebSocket 时,必须在连接期间保持中间件管道运行。从您的日志中,它看起来好像在连接后立即关闭了 Web 套接字。一旦端点被接受,就可以看到它处理 如果你把这个放在 await Echo(context, webSocket);接受网络套接字后。 add 从链接添加回显代码 【参考方案1】:我已经使用这些文档在 ASP.NET 核心中实现了一个 WebSocket 服务器,它对我来说效果很好:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-3.1
主要思想是,在您接受带有AcceptWebSocketAsync()
的请求后,您获取返回的WebSocket
对象并使用它来发送和接收。通常,您会创建一个循环,调用ReceiveAsync
直到满足某些条件(当您收到特定消息时确定会话已完成,或者客户端断开连接等)。正如文档所述,When using a WebSocket, you must keep the middleware pipeline running for the duration of the connection.
因此,如果您将 WebSocket
连接传递给后台工作人员以执行发送/接收,您需要在与该客户端交互期间保持该管道打开。然后,当您完成后,您会向中间件发出信号,表明连接已完成并且可以展开。
我怀疑不保持连接打开和循环是您的问题。我之前没有在 WebSockets 上使用过 MapConnectionHandler
,所以这可能行不通,但上述策略可能会对您有所帮助,或者像这样使用后台工作人员关注文档:
app.Use(async (context, next) =>
var socket = await context.WebSockets.AcceptWebSocketAsync();
var socketFinishedTcs = new TaskCompletionSource<object>();
BackgroundSocketProcessor.AddSocket(socket, socketFinishedTcs);
await socketFinishedTcs.Task;
);
【讨论】:
嘿,我试过循环等等,似乎MapConnectionHandler
不适合它。构建一个合适的中间件为我解决了这个问题。
我得到未定义的BackgroundSocketProcessor?我错过了什么图书馆?
如何将套接字实际传递给后台工作人员,BackgroundSocketProcessor.AddSocket
中的内容是什么?【参考方案2】:
所以,我完成了我的目标。完整的用例在这里:https://github.com/Yucked/Rhapsody/blob/beta/src/Controllers/WebSocketHandler.cs
此方法使用System.IO.Pipelines
。我没有旧的源代码,因为我废弃了它,甚至在保持管道打开之后也无法弄清楚为什么连接被丢弃,但是现在它可以工作了!
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
endpoints.MapConnectionHandler<WebSocketHandler>("/player/playerId");
);
public override async Task OnConnectedAsync(ConnectionContext connection)
var httpContext = connection.GetHttpContext();
if (!httpContext.WebSockets.IsWebSocketRequest)
await httpContext.Response.CompleteAsync();
return;
await httpContext.WebSockets.AcceptWebSocketAsync()
.ContinueWith(async task =>
var webSocket = await task;
await HandleConnectionAsync(webSocket);
);
private async Task HandleConnectionAsync(WebSocket websocket)
try
do
var memory = writer.GetMemory(BUFFER_SIZE);
var receiveResult = await webSocket.ReceiveAsync(memory, CancellationToken.None);
if (!receiveResult.EndOfMessage)
writer.Advance(receiveResult.Count);
continue;
await writer.FlushAsync();
while (webSocket.State == WebSocketState.Open);
catch (Exception exception)
await writer.CompleteAsync(exception);
【讨论】:
以上是关于ASP.NET Core WebSockets的主要内容,如果未能解决你的问题,请参考以下文章
Asp.NET Core进阶 第四篇 Asp.Net Core Blazor框架
.NET Core 1.0ASP.NET Core 1.0和EF Core 1.0简介
深入研究 Mini ASP.NET Core(迷你 ASP.NET Core),看看 ASP.NET Core 内部到底是如何运行的
.Net Core 学习 - ASP.NET Core 概念学习
ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 14. ASP.NET Core Identity 入门