System.Net.WebSockets 是否有问题,或者我只是不理解 websockets?

问题描述 投票:0回答:1

我正在尝试编写一个在.Net 8 中使用 System.Net.WebSockets 的程序,但我没有看到我期望的结果。这是一个不起作用的简化示例:

[ApiController]
[Route("[controller]")]
public class WebSocketController : ControllerBase
{
    [HttpGet]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await ReceiveMessages(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

    private static async Task ReceiveMessages(WebSocket webSocket)
    {
        WebSocketReceiveResult receiveResult;
        var buffer = new byte[1];
        do
        {
            receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        } while (!receiveResult.CloseStatus.HasValue);

        await webSocket.CloseAsync(
            receiveResult.CloseStatus.Value,
            receiveResult.CloseStatusDescription,
            CancellationToken.None);
    }
}

客户端发送的第一条消息将被成功接收,然后

ReceiveAsync
将不会与客户端发送的任何其他消息一致地再次返回。

如果我添加另一行,在收到每条消息后将消息发送回客户端,则程序在接收客户端发送的每条消息时不会出现问题:

private static async Task ReceiveMessages(WebSocket webSocket)
{
    WebSocketReceiveResult receiveResult;
    var buffer = new byte[1];
    do
    {
        receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
    } while (!receiveResult.CloseStatus.HasValue);

    await webSocket.CloseAsync(
        receiveResult.CloseStatus.Value,
        receiveResult.CloseStatusDescription,
        CancellationToken.None);
}

在我的用例中,我不需要每次收到消息时都将消息发送回客户端。在查看了RFCMicrosoft的文档后,顶部代码块似乎应该按原样工作。我是否误解了有关 websockets 或 System.Net.WebSockets 的内容,或者这是 System.Net.WebSockets 的错误?

c# .net asp.net-core websocket
1个回答
0
投票

我最近也遇到了同样的问题。如果我错了,请纠正我,但就我而言,一旦 Get 请求完成,WebSocket 连接就会终止。

为了解决这个问题,我使用了 AutoResetEvent,尽管可能有更好的解决方案。然而,对于我的项目来说,这是迄今为止最好的解决方案。

在您的代码中,实现将如下所示:

[HttpGet]
public async Task Get()
{
    if (HttpContext.WebSockets.IsWebSocketRequest)
    {
        var stopHandle = new AutoResetEvent(false);

        using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
        await ReceiveMessages(webSocket, stopHandle);
        
        stopHandle.WaitOne();
    }
    else
    {
        HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
    }
}

这个 stopHandle 现在在那里等待,直到被告知继续。

这正是您关闭连接时告诉它的内容。

    private static async Task ReceiveMessages(WebSocket webSocket, AutoResetEvent stopHandle)
    {
        WebSocketReceiveResult receiveResult;
        var buffer = new byte[1];
        do
        {
            receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
        } while (!receiveResult.CloseStatus.HasValue);

        await webSocket.CloseAsync(
            receiveResult.CloseStatus.Value,
            receiveResult.CloseStatusDescription,
            CancellationToken.None);
        stopHandle.Set(); // Tell the stopHandle not to wait any longer
    }

正如我所说。它可能相对没有吸引力,但它确实有效。

顺便说一句。不要忘记将“UseWebSockets”中间件添加到请求管道中。

app.UseWebSockets();
© www.soinside.com 2019 - 2024. All rights reserved.