I am using websocket in .net core and my issue is that when the client is no longer connected to the internet his websocket connection closes but as per the server the client is still connected, i am not receiving any disconnection packet, in addition i am publishing the websocket on Azure and i have set the property WebSocket=ON and AlwaysOn=On. Please can you help me !
references:
https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/websockets/samples
https://code.msdn.microsoft.com/How-to-use-websocket-with-2c6d8b6e/sourcecode?fileId=172049&pathId=1358619959
i have the below server:
public async Task Invoke(HttpContext context)
{
if (context.WebSockets.IsWebSocketRequest)
{
SocketUserObject socketUser = new SocketUserObject();
if (_webSocketLogic.IsAuthorizedUser(context, ref socketUser, _operation))
{
var connection = await _webSocketHandler.OnConnected(context, socketUser, _operation);
if (connection != null)
{
await _webSocketHandler.ListenConnection(connection);
}
else
{
context.Response.StatusCode = 404;
}
}
else
{
context.Response.StatusCode = 404;
}
}
}
public async Task ListenConnection(WebSocketConnection connection)
{
var buffer = new byte[BufferSize];
try
{
while (connection.WebSocket.State == WebSocketState.Open)
{
var result = await connection.WebSocket.ReceiveAsync(
buffer: new ArraySegment<byte>(buffer),
cancellationToken: CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
await ReceiveAsync(connection, message, _operation2);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await OnDisconnected(connection, _operation2);
}
}
}
catch (Exception ex)
{
_logging.TraceError(ex, _operation);
}
_logging.TraceLog(System.Reflection.MethodInfo.GetCurrentMethod(), _operation, "after State ", connection.WebSocket.State.ToString());
}
And I have added in the startup the below:
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(1),
ReceiveBufferSize = 4 * 1024
};
app.UseWebSockets(webSocketOptions);
I also tried adding this to the web.config file created on Azure from Kudu console:
<system.webServer>
<webSocket enabled="true" receiveBufferLimit="4194304" pingInterval="00:01:00">
</webSocket>
</system.webServer>
and this is my client :
public void StartReceiving(int modulo)
{
RunWebSockets().GetAwaiter().GetResult();
}
private async Task RunWebSockets()
{
var client = new ClientWebSocket();
try
{
client.Options.SetRequestHeader("id_handset", "1");
await client.ConnectAsync(new Uri(url), CancellationToken.None);
Console.WriteLine("Connected!");
var sending = Task.Run(async () =>
{
string line;
if (client.State == WebSocketState.Open)
{
SocketOperation.Start(_socketOperation, client);
}
});
var receiving = Receiving(client);
await Task.WhenAll(sending, receiving);
}
catch (Exception ex)
{
if (client.State == WebSocketState.Open)
{
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
SocketOperation.StopConsole();
RunWebSockets().GetAwaiter().GetResult();
}
}
private async Task Receiving(ClientWebSocket client)
{
var buffer = new byte[1024 * 4];
while (true)
{
var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, result.Count));
else if (result.MessageType == WebSocketMessageType.Close)
{
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
SocketOperation.StopConsole();
RunWebSockets().GetAwaiter().GetResult();
//await client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
break;
}
}
}
⚠Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
@anurse can we provide guidance on connection state?
The suggestion if you care about detecting client disconnects is to timeout if you haven't heard from the other side within a certain time window. If you aren't always sending messages and don't want to timeout just because the connection goes idle, you need to send "ping" messages to tell the other side that you're still there and still want the connection to stay open. This is what SignalR does, for example.
A disconnect message only occurs if the client is actually there to send it, so if the client just loses internet connection you get no disconnect message because the client has no connection over which to send the disconnect message.
@tdykstra looks like good advice to add to the article.
@anurse so now you mean i have to use SignalR instead which makes the ping/pong messages itself? or i have to make my own ping/pong for the websocket .net core?
@anurse and if i need to keep using websocket (because my client are ios swift and signalR is still not supported) how can i implement ping/pong in the websocket module?
so now you mean i have to use SignalR instead which makes the ping/pong messages itself? or i have to make my own ping/pong for the websocket .net core?
Yes, either of those would be reasonable ways to accomplish this.
because my client are ios swift and signalR is still not supported
There is an unofficial (but well-maintained) Swift client for SignalR available here: https://github.com/moozzyk/SignalR-Client-Swift - The author is a former member of the SignalR team. It's not "official" support, but it does provide a native client API for SignalR.
how can i implement ping/pong in the websocket module?
I don't have a complete sample available for you, but the basic idea is as I described. You can't know for sure that a client has disconnected, so you need to set up a system that can tell you for sure that a client is connected, by having the client use a timer to make sure it always sends a message every X seconds. Then, when waiting for a message on the server, if a message hasn't arrived within 2*X (usually it's good to leave extra time for network delays that may be holding up the ping message), terminate the connection and report that the client disconnected.
@tdykstra can you add this note?