1

I am creating a lib to listen to server notifications (more than 100,000 requests per hour), when using WebSocketSharp it is receiving all 100,000 notifications but there is memory leak (server goes out of memory after couple of hours).

When using System.Net.WebSockets, the memory cleared correctly (no memory leak) but I only receive 60,000 notifications (some messages are missing). I am using the function below to receive the notification (changing options and buffer didn't help):

async Task Receive()
{
    Task RunningTask = Task.Factory.StartNew(async () =>
    {
        await HandleMessage(channel.Reader);
    });
    while (WebSocket.State == WebSocketState.Open)
    {
        try
        {
            //var buffer = new byte[256];
            var maxSize = BufferSize;
            var framePayload = new Memory<byte>(new byte[maxSize]);
            var buffer = new Memory<byte>(new byte[maxSize / 2]);
            ValueWebSocketReceiveResult result;
            DateTime receiveTime = DateTime.Now;
            int framePayloadSize = 0;
            do
            {
                result = await WebSocket.ReceiveAsync(buffer, CancellationToken.None);
                receiveTime = DateTime.Now;
                var data = buffer.Slice(0, result.Count);
                if (framePayloadSize + result.Count > maxSize)
                {
                    var tempFramePayload = new Memory<byte>(new byte[maxSize]);
                    framePayload.CopyTo(tempFramePayload);
                    maxSize *= 2;
                    framePayload = new Memory<byte>(new byte[maxSize]);
                    tempFramePayload.CopyTo(framePayload);
                }
                data.CopyTo(framePayload.Slice(framePayloadSize, result.Count));
                framePayloadSize += result.Count;
            } while (!result.EndOfMessage);

            if (result.Count != 0)
            {
                try
                {

                    if (result.MessageType == WebSocketMessageType.Close)
                    {
                        _log.LogInformation("DotNetWS Message Close.");
                        await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
                        channel.Writer.Complete();
                    }
                    else
                    {
                        await channel.Writer.WriteAsync(new() { Payload = framePayload, PayloadSize = framePayloadSize });
                    }
                }
                catch (Exception ex)
                {
                    _log.LogError("DotNetWS Error: {ErrorMessage}", ex.Message);
                }
            }
        }
        catch (Exception e)
        {
            _log.LogError("DotNetWS Error: {ErrorMessage}", e.Message);
        }
    }
    _log.LogInformation("DotNetWS Channel is closed");
}

Here is the Webscoketsharp doing the same thing, it is working fine (except for the memory leak part).

WebSocket = new WebSocket(uri);
WebSocket.OnMessage += delegate (object sender, MessageEventArgs e)
{
    try
    {
        NotificationData<JObject> notificationData = JsonConvert.DeserializeObject<GCPayload>(e.Data);
        .......
    }
    catch (Exception value)
    {
        Console.WriteLine(value);
    }
};
3
  • Nit: (this is not why you're not getting all messages): you can streamline a bit by just assigning tempFramePayload directly to framePayload after the first copy instead of allocating and copying again. Commented Oct 24 at 16:05
  • What is channel? How is it declared and initialized? Commented Oct 25 at 7:25
  • Channel is System.Threading.Channels.Channel, the idea is to prevent reader from getting stuck if processing of the message took long time. System.Threading.Channels.Channel<GCPayload> channel = System.Threading.Channels.Channel.CreateUnbounded<GCPayload>( new System.Threading.Channels.UnboundedChannelOptions { SingleWriter = false, SingleReader = false, AllowSynchronousContinuations = true }); Commented Oct 25 at 8:38

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.