TcpListener ist queuing-verbindungen schneller als ich kann Sie löschen
Wie ich es verstehe, TcpListener
Warteschlange, die verbindungen, sobald Sie rufen Start()
. Jedes mal, wenn Sie anrufen AcceptTcpClient
(oder BeginAcceptTcpClient
), wird er aus der Warteschlange entfernt ein Element aus der Warteschlange.
Wenn wir laden, testen unsere TcpListener
app durch senden von 1.000 verbindungen, um es auf einmal, die Warteschlange baut sich weit schneller als wir es klar, führt (eventuell) zu timeouts vom client, da es nicht eine Antwort zu bekommen, denn die Verbindung war noch in der Warteschlange. Jedoch wird der server nicht angezeigt unter viel Druck, unsere app nicht verbrauchen viel CPU-Zeit und die anderen überwachten Ressourcen auf dem Rechner nicht ins Schwitzen zu geraten. Es fühlt sich an wie wir sind, läuft nicht effizient genug, gerade jetzt.
Wir fordern BeginAcceptTcpListener
und dann sofort die übergabe an eine ThreadPool
thread, um tatsächlich tun die Arbeit, dann ruft BeginAcceptTcpClient
wieder. Der Arbeitsaufwand scheint nicht Druck auf die Maschine, es ist im Grunde nur eine 3-Sekunden-Schlaf, gefolgt von einem Wörterbuch nachschlagen und dann ein 100 byte schreiben, um die TcpClient
's stream.
Hier ist die TcpListener
code verwenden wir:
//Thread signal.
private static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
public void DoBeginAcceptTcpClient(TcpListener listener)
{
//Set the event to nonsignaled state.
tcpClientConnected.Reset();
listener.BeginAcceptTcpClient(
new AsyncCallback(DoAcceptTcpClientCallback),
listener);
//Wait for signal
tcpClientConnected.WaitOne();
}
public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
//Get the listener that handles the client request, and the TcpClient
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
if (inProduction)
ThreadPool.QueueUserWorkItem(state => HandleTcpRequest(client, serverCertificate)); //With SSL
else
ThreadPool.QueueUserWorkItem(state => HandleTcpRequest(client)); //Without SSL
//Signal the calling thread to continue.
tcpClientConnected.Set();
}
public void Start()
{
currentHandledRequests = 0;
tcpListener = new TcpListener(IPAddress.Any, 10000);
try
{
tcpListener.Start();
while (true)
DoBeginAcceptTcpClient(tcpListener);
}
catch (SocketException)
{
//The TcpListener is shutting down, exit gracefully
CheckBuffer();
return;
}
}
Ich nehme an die Antwort wird im Zusammenhang mit der Verwendung Sockets
statt TcpListener
oder zumindest mit TcpListener.AcceptSocket
werden, aber ich fragte mich, wie würden wir tun?
Einer Idee, die wir hatten, war ein Telefonat mit AcceptTcpClient
und sofort Enqueue
die TcpClient
in einer von mehreren Queue<TcpClient>
Objekte. So, könnten wir Umfrage die Warteschlangen in separaten threads (eine queue pro thread), ohne Monitore, die blockieren könnten den thread während der Wartezeit für andere Dequeue
Operationen. Jede queue thread könnte dann ThreadPool.QueueUserWorkItem
zu haben, die Arbeit in einem ThreadPool
thread und bewegen Sie dann auf entfernen am nächsten TcpClient
in der Warteschlange. Würden Sie empfehlen diese Vorgehensweise, oder ist unser problem, dass wir TcpListener
und kein Betrag der schnelle dequeueing wird, dass zu beheben?
- Ich denke, Sie haben vielleicht eine irrige Annahme. Die eingehenden verbindungen werden verworfen, nicht fallen gelassen aus der Schlange. Sie haben es nie in die Warteschlange, weil die queue war bereits voll. Sie haben die option eine größere Länge der Warteschlange. Das wird das problem zu lindern etwas. Das eigentliche problem ist, dass es nicht sehr realistisch-slam-server mit verbindet schnell. Ein server, der ist gebaut, um zu behandeln 1k-clients in der Regel noch erfordert die Verbindung zu kommen in auf einem getakteten Tempo.
- Versuchen Sie, diese mit einer größeren "Nachholbedarf" Wert: "msdn.microsoft.com/en-us/library/5kh8wf6s(v=VS.100).aspx
- MSDN sagt, dass der TcpListener eine SocketException ausgelöst, wenn die queue-Größe ist überschritten, ich habe nicht gesehen, alle SocketExceptions (die CheckBuffer Methode logs), also bin ich davon ausgegangen, ich hatte nicht die Größenbeschränkung erreicht noch. Aber das ist ein guter Punkt re 1k-verbindungen.
- Nur um zu klären, diejenigen, die SocketExceptions geworfen werden, auf dem client, nicht der server.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Habe ich bis Schlagsahne einige code, der verwendet sockets direkt, aber mir fehlen die Mittel für das ausführen eines load-test mit 1000 Kunden. Könnten Sie bitte versuchen, zu testen, wie dieser code im Vergleich zu Ihrer aktuellen Lösung? Ich wäre sehr an den Ergebnissen interessiert, wie Baue ich einen server, der muss akzeptieren, dass eine Menge von verbindungen, wie auch jetzt.
Es sei denn, ich bin fehlt etwas, die Sie aufrufen BeingAcceptTcpClient, die ist asynchron, aber dann bist du aufrufen WaitOne() zu warten, bis der asynchrone code abgeschlossen ist , die effektiv macht den Prozess synchron. Ihr code kann nur akzeptieren, ein client zu einem Zeitpunkt. Oder bin ich völlig verrückt geworden? Zumindest dies scheint wie eine Menge von Kontext-switching für nichts.
Es wurde angedeutet, in der andere Fragen, aber ich würde vorschlagen, in Ihrem tcpListener.Start () - Methode verwenden Sie die überladung, die ermöglicht Sie, um den Rückstand auf einen Wert größer als die maximale Anzahl der verbindungen, die Sie erwarten auf einmal:
Grundsätzlich diese option legt fest, nach wie vielen ausstehenden TCP-verbindungen sind erlaubt, die warten auf einen Accept aufgerufen werden. Wenn Sie nicht akzeptieren, verbindungen schnell genug, und das backlog füllt sich, die TCP-verbindungen werden automatisch abgelehnt und Sie werden nicht einmal die chance bekommen, diese zu verarbeiten.
Wie andere erwähnt haben, die andere Möglichkeit ist die Beschleunigung, wie schnell Sie Bearbeiten die eingehenden verbindungen. Sie immer noch, jedoch sollte der Rückstand auf einen höheren Wert, auch wenn Sie können die Geschwindigkeit der Zeit akzeptieren.
Nur ein Vorschlag : warum nicht akzeptieren die Kunden die synchron (durch die Verwendung
AcceptTcpClient
stattBeginAcceptTcpClient
), und dann den client in einem neuen thread ? Auf diese Weise werden Sie nicht haben, zu warten für einen client, um verarbeitet werden, bevor Sie akzeptieren kann, die nächste.Ist die erste Sache, sich zu Fragen: "ist 1000 verbindungen auf einmal vernünftig". Ich persönlich denke, es ist unwahrscheinlich, dass Sie in dieser situation. Mehr wahrscheinlich, Sie haben 1000 verbindungen, die über einen kurzen Zeitraum.
Ich habe einen TCP-test-Programm, dass ich verwende zum testen meinen server framework, es können Dinge tun, wie X-verbindungen insgesamt in Chargen von Y mit einem Abstand von Z ms zwischen jeder charge, die finde ich persönlich mehr der realen Welt als 'überwiegende Anzahl alle auf einmal'. Es ist kostenlos, es könnte helfen, können Sie es von hier: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html
Wie schon andere gesagt haben, erhöhen Sie die listen backlog-Prozess die verbindungen schneller, die asynchrone akzeptiert, wenn möglich...