javascript asp.net WebSocket在操作完成后保持活动状态

7gyucuyw  于 2023-01-24  发布在  Java
关注(0)|答案(2)|浏览(164)

在asp.netcore(5.0)Web应用程序中,是否可以在没有无限while循环的情况下保持套接字活动?(while (webSocket.State == WebSocketState.Open)如果循环是唯一的方法,这不是非常低效吗?
这基本上是我希望达到的目标

public class SocketController : Controller
{

  [HttpGet]
  [Route("Connect")]
  public async Task ConnectAsync()
  {
    if (HttpContext.WebSockets.IsWebSocketRequest)
    {
      var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
      SocketManager.registerSocket(User, webSocket);
      var outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes("pong"));
      await webSocket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
    }
    else
    {
      HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
    }
  }

}

这似乎行得通,但似乎不对

public class SocketController : Controller
{

  [HttpGet]
  [Route("Connect")]
  public async Task ConnectAsync()
  {
    if (HttpContext.WebSockets.IsWebSocketRequest)
    {
      var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
      // stuff
      while (webSocket.State == WebSocketState.Open) ;
    }
    else
    {
      HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
    }
  }

}

检查套接字关闭的最小示例:

var socket = new WebSocket("wss://localhost:44331/Socket/Connect");
socket.onclose = function (err) {
    console.log("CLOSED");
    console.error(err);
};

如果我删除循环,连接在JS端关闭,当动作完成执行时,输出:

CLOSED
{
    isTrusted: true,
    bubbles: false,
    cancelBubble: false,
    cancelable: false,
    code: 1006,
    composed: false,
    currentTarget: [WebSocket Object],
    defaultPrevented: false,
    eventPhase: 0,
    path: [],
    reason: "",
    returnValue: true,
    srcElement: [WebSocket Object],
    target: [WebSocket Object],
    timeStamp: 958.5999999998603,
    type: "close",
    wasClean: false
}
uxh89sit

uxh89sit1#

WebSocket使用ping/pong心跳来保持活动。
Ping帧可用作保活或用作验证远程端点仍在响应的手段。
但是,当客户端收到Ping时,必须向服务器发回Pong
当收到Ping帧时,端点必须发送Pong帧作为响应,除非它已经收到Close帧。它应该尽快用Pong帧响应。
您可以使用KeepAliveInterval来设置向客户端发送“ping”帧以确保代理保持连接打开的频率。默认值为两分钟。

var webSocketOptions = new WebSocketOptions() 
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

在您的代码中,while (webSocket.State == WebSocketState.Open)只是检查WebSocket的状态,它不会使websocket保持活动状态。
当客户端由于连接丢失而断开连接时,不会自动通知服务器。只有当客户端发送断开连接消息时,服务器才会接收到该消息,如果Internet连接丢失,则无法接收该消息。如果您希望在发生这种情况时采取某些操作,请设置在特定时间窗口内未从客户端接收到任何消息后的超时。

dced5bon

dced5bon2#

即使晚了一点实际上,您的解决方案的问题在于,您的while (webSocket.State == WebSocketState.Open);执行CPU密集型轮询,应该避免。
然而,我也感受到了同样的“问题”,这就是目前我的解决方案。不同的是,只有在循环块中接收到作为await ws.ReceiveAsync的东西时,才会处理循环。

private async static Task ReceiveUntilClosed(WebSocket ws)
{
    var buffer = new byte[1024 * 4];

    var receiveResult = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

    while (!receiveResult.CloseStatus.HasValue)
    {
        HandleRequestResult(ws, receiveResult); // Your receive method handle stuff (or sending)
        var receiveResult = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }

    Console.WriteLine("ws closing connection...");
    await ws.CloseAsync(
        receiveResult.CloseStatus.Value,
        receiveResult.CloseStatusDescription,
        CancellationToken.None);
    Console.WriteLine("ws connection closed");
}

在Connect内部调用该方法,如下所示:

[HttpGet]
  [Route("Connect")]
  public async Task ConnectAsync()
  {
    if (HttpContext.WebSockets.IsWebSocketRequest)
    {
      var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
      SocketManager.registerSocket(User, webSocket);
      ReceiveUntilClosed(webSocket); // Here
    }
    else
    {
      HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
    }
  }

在我的例子中,我还添加了一个cancel-token,这样我就可以主动关闭连接。
如果有人有更好的解决方案,请随意纠正我:)

相关问题