I am writing a simple websocket server with Microsoft.NETCore.App 1.1.0. My program is based on this tutorial (code of the tutorial: github). Everything works fine so far: I can connect to my server using a little javascript program. The server responses with an echo of my request. But after this response the socket is closed.
This is the code of my SocketHandler.cs
public class SocketHandler
{
public const int BufferSize = 4096;
private WebSocket _socket;
SocketHandler(WebSocket socket)
{
_socket = socket;
}
async Task EchoLoop()
{
var requestBuffer = new ArraySegment<byte>(new byte[BufferSize]);
var request = await _socket.ReceiveAsync(requestBuffer, CancellationToken.None);
var requestText = Encoding.UTF8.GetString(requestBuffer.Array,
requestBuffer.Offset, requestBuffer.Count);
var responseBytes = Encoding.UTF8.GetBytes(requestText);
var responseBuffer = new ArraySegment<byte>(responseBytes);
await _socket.SendAsync(responseBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
static async Task Acceptor(HttpContext httpContext, Func<Task> next)
{
if (!httpContext.WebSockets.IsWebSocketRequest) return;
var socket = await httpContext.WebSockets.AcceptWebSocketAsync();
if (socket != null && socket.State == WebSocketState.Open)
{
var h = new SocketHandler(socket);
await h.EchoLoop();
}
else
{
await next();
}
}
public static void Map(IApplicationBuilder app)
{
app.UseWebSockets();
app.Use(Acceptor);
}
}
This is mostly identical to the code in the tutorial except one thing: I do not close the socket in my client after sending a message. Unfortunately I receive a 'onclose' event after I received the server echo.
I wonder how I can listen to socket events on the server like 'onopen', 'onmassage' etc. like I have seen in WebSocketHandler. The method to register such a handler is gone in NetCore.
The method AcceptWebSocketAsync() seems to always create a new socket. What if the client already did a handshake? Hw do I store this established connection and react to its events?
I want to hold all socket connections in a server-side list and manage them (broadcast messages, close sockets after a timeout etc.). Do I have to use a HTTP session to identify the client and map it to the open socket in my list? I found this nice tutorial for implementing sessions but I do not know if I am on the right way with this.
Does the socket connection itself have an ID that I could use? Or how is the connection identified?
Thank you :)
[UPDATE]
I found a solution to keep the socket open. I added a while-loop to the acceptor task:
static async Task Acceptor(HttpContext httpContext, Func<Task> next)
{
if (!httpContext.WebSockets.IsWebSocketRequest) return;
var socket = await httpContext.WebSockets.AcceptWebSocketAsync();
if (socket != null)
{
var h = new SocketHandler(socket);
while (socket.State == WebSocketState.Open)
{
await h.EchoLoop();
}
}
await next();
}
It seems to me that the socket gets closed if the socket object looses its scope (and gets removed by the gc). I do not know if this assumption is right. I do not know if this solution is a good idea in terms of CPU performance since I am waiting for the socket in a while loop. Any ideas?