SignalR/SignalR — Issue #214: Server not recognising remote disconnections
Author: adsteruk
Created: 2012-02-29 14:15:57+00:00
State: open

Using the latest source code I've got a simple server and a client that makes 100 connections. I run the server, followed by the client, once the client says it has 100 active connections I close it down.

If I run the client locally then all works well. However if the client is on a remote machine the Server never raises a disconnected event for most of the connections (it only sees 2). Memory profiling at this point indicates that the server is still holding memory for the remaining connections.

After further testing it appears to be related to the restriction on outbound http connections, if you modify the client config to allow many connections (\\\) it will work flawlessly. But this still leaves the problem that its possible for a client to maliciously create memory leaks in the Server.

```
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using SignalR;
using SignalR.Hosting;

namespace SimpleSignalRServer
{
class Program
{
static void Main(string[] args)
{
new Server();
Console.WriteLine("Server running...");
Console.ReadKey();
}
}

internal class Server
{
public Server()
{
SignalR.Hosting.Self.Server server = new SignalR.Hosting.Self.Server("http://192.168.10.123:5000/");
server.MapConnection("/test");
server.Start();
}
}

internal class TestConnection : PersistentConnection
{
private static int connections;
private static int disconnections;

protected override Task OnConnectedAsync(IRequest request, IEnumerable groups, string connectionId)
{
Console.WriteLine("Connection from: " + connectionId);
Connection.Broadcast(connectionId, "connected");
Interlocked.Increment(ref connections);
return base.OnConnectedAsync(request, groups, connectionId);
}

protected override Task OnReconnectedAsync(IRequest request, IEnumerable groups, string connectionId)
{
Console.WriteLine("Reconnection from: " + connectionId);
return base.OnReconnectedAsync(request, groups, connectionId);
}

protected override Task OnDisconnectAsync(string connectionId)
{
Console.WriteLine("Disconnection from: " + connectionId);
Interlocked.Increment(ref disconnections);
Console.WriteLine("Total connections: " + connections);
Console.WriteLine("Total disconnections: " + disconnections);
return base.OnDisconnectAsync(connectionId);
}

protected override Task OnReceivedAsync(string connectionId, string data)
{
Console.WriteLine("received: " + data);
return base.OnReceivedAsync(connectionId, data);
}
}

}
```

```
using System;
using System.Threading;
using SignalR.Client;
using SignalR.Client.Transports;

namespace SimpleSignalRClient
{
class Program
{
private static int NoClients = 100;

static void Main(string[] args)
{
for (int i = 0; i < NoClients; i++)
{
new Client(i);
Console.WriteLine("Client {0} running...", i + 1);
}
Console.ReadKey();
}
}

internal class Client
{
private static int connections;
private static int active;

public Client(int clientNo)
{
Connection connection = new Connection("http://192.168.10.123:5000/test");
connection.Received += OnReceive;
connection.Start(new LongPollingTransport());
//connection.Start(new ServerSentEventsTransport());
//connection.Start();
Interlocked.Increment(ref connections);
Console.WriteLine(connection.ConnectionId);
}

void OnReceive(string data)
{
if (data == "connected")
{
Interlocked.Increment(ref active);
}
Console.WriteLine("connections: " + connections);
Console.WriteLine("active: " + active);
}
}
}
```