查找WebSocket服务器内存泄漏

时间:2018-03-26 13:13:48

标签: websocket .net-core webserver

大家好我正在测试一个用Asp .Net Core 2.0编写的websocket服务器,我相信我有内存泄漏。即使我试图处理可能引起关注的一切,我也找不到它。
测试是连续进行的,并且在达到稳定时采用了撞锤的值(从5秒到20秒不等)。
使用普通的任务管理器监视器测量占用的RAM。

测试工具
Thorhttps://github.com/observing/thor
 命令:thor --amount [amount] ws://[HostIP (localhost)]:[portnumber]

结果

Connections | RAM Consumed at the end of test (GB):

0             4.54
50            4.55
100           4.55
150           4.61
200           4.68
300           4.76  
400           4.59
400           4.59
500           4.62
500           4.65
550           4.65

WebSocket服务器:

SocketMiddleware - 由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 - 这是处理所有已打开的套接字的嫌疑人

  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");
                }
            }
        }

客户端 - socketWrapper,它对套接字执行所有必需的操作并存储要由跟踪器使用的临时数据

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>();
        }

P.S: 请求之间没有关闭服务器。它可以是并发字典吗?除此之外,客户端的引用被清理,客户端被丢弃,套接字被关闭。字符串构建器无法处理,跟踪器/中间件只要应用程序存在,就会活着。

0 个答案:

没有答案