Hello i have developed a websocket server and i would like to know if there is any problem in creating a service (which is used by the middleware)that has a method which is used for every websocket request.This method is async and it starts an infinite loop for the request (send-receive). I would like to know if there is any problem memory-wise in the following scenario:
Object A
is created once.
A has a method we'll call MyInfiniteFunc
.MyInfiniteFunc
will start an infinite loop in its bowels.
If two other objects will call A.MyInfiniteFunc()
(from different threads )more specifically on different HttpContext
's,if the two requests overlap will there be any problem with MyInfiniteFunc
?
I believe MyInfiniteFunc
will be "instantiated" as many times it is needed or am i wrong?
P.S MyInfiniteFunc
does not have any shared resource of which i have to take care of to be thread-safe.
Concrete problem:
SocketMiddleware -used by the appbuilder:
public class SocketMiddleware
{
public byte[] ToSegment(string message) => System.Text.Encoding.UTF8.GetBytes(message);
ClientTracker clientTracker; //the socket clients tracker this is the object we're speaking of
RequestDelegate next;
public SocketMiddleware(ClientTracker tracker,RequestDelegate del)
{
this.clientTracker=tracker;
this.next=del;
}
public async Task Invoke(HttpContext context)
{
if(!context.WebSockets.IsWebSocketRequest)
{
await this.next.Invoke(context);
return;
}
await this.clientTracker.AddClient(context.WebSockets);
}
}
SocketTracker- this is the suspect which is dealing with all the opened sockets
public class ClientTracker
{
ConcurrentDictionary<string, Client> clientMap = new ConcurrentDictionary<string, Client>();
public string CreateConnectionID() => Guid.NewGuid().ToString();
public string GetIDOfSocket(WebSocket socket) => this.clientMap.First(x => x.Value.webSocket.Equals(socket)).Key;
public Client GetClientByID(string id)
{
this.clientMap.TryGetValue(id, out Client client);
return client;
}
public async Task AddClient(WebSocketManager manager)
{
using (WebSocket socket = await manager.AcceptWebSocketAsync())
{
Client newClient = Client.CreateClient(socket, CreateConnectionID());
if(clientMap.TryAdd(newClient.clientID, newClient))
{
await ReceiveMessage(newClient);
}
}
}
public async Task ReceiveMessage(Client client)
{
while (client.webSocket.State == WebSocketState.Open)
{
WebSocketReceiveResult result = await client.ReceiveResult();
//dosomething with result...
if (result.MessageType == WebSocketMessageType.Close)
{
await client.webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closed", CancellationToken.None);
break;
}
//send custom message
await client.SendMessage("lala");
}
}
}
Client- socketWrapper which performs all required operations on the socket and stores temporary data to be used by the tracker
public class Client
{
//Fields
public readonly WebSocket webSocket;
public readonly string clientID;
public StringBuilder tempData;
//Auxiliary
private const int BufferSize = 1024 * 4;
public static Client CreateClient(WebSocket socket, string id)
{
Client client = new Client(socket, id);
return client;
}
public Client(WebSocket socket, string id)
{
this.webSocket = socket;
this.clientID = id;
tempData = new StringBuilder();
}
public async Task<WebSocketReceiveResult> ReceiveResult()
{
tempData.Clear();
ArraySegment<byte> segment = new ArraySegment<byte>(new byte[BufferSize]);
WebSocketReceiveResult result = await this.webSocket.ReceiveAsync(segment, CancellationToken.None);
tempData.Append(BitConverter.ToString(segment.Array));
return result;
}
public async Task SendMessage(string message)
{
byte[] bytes = Encoding.UTF8.GetBytes(message);
await this.webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<ClientTracker>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseWebSockets();
app.UseMiddleware<SocketMiddleware>();
}
As you can see i need the SocketTracker to perform businesslogic on multiple sockets . I am considering accepting the socket in the middleware and then just add the socket to the tracker for tracking,and afterwards start the infinite loop in the middleware.But i am not sure about my first implementation.