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



在asp.net核心(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
}

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保持活动状态。

当客户端由于连接丢失而断开连接时,不会自动通知服务器。只有当客户端发送断开连接消息时,服务器才会接收到断开连接的消息,而如果互联网连接丢失,则无法执行此操作。如果您想在发生这种情况时采取一些操作,请在某个时间窗口内没有收到来自客户端的任何消息后设置超时。

即使有点晚:解决方案的问题实际上是,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;
}
}

在我的情况下,我还添加了一个取消令牌,这样我就可以主动关闭连接。

如果有人有更好的解决方案,请随时告诉我:(