it-swarm.com.de

Random "Eine bestehende Verbindung wurde vom Remote-Host zwangsweise geschlossen." nach einer TCP zurücksetzen

Ich habe zwei Teile, einen Client und einen Server. Und ich versuche, Daten (Größe> 5840 Bytes) vom Client an den Server zu senden, und dann sendet der Server die Daten zurück. Ich schleife das mehrmals und warte zwischen jedem Mal eine Sekunde. Irgendwann stürzt die Server-Anwendung ab, der Fehler scheint sehr zufällig zu sein:

Nicht behandelte Ausnahme: System.IO.IOException: Daten aus der Transportverbindung können nicht gelesen werden: Eine vorhandene Verbindung wurde vom Remote-Host zwangsweise geschlossen. --->

System.Net.Sockets.SocketException: Eine vorhandene Verbindung wurde vom Remote-Host zwangsweise geschlossen

at System.Net.Sockets.Socket.Receive (Byte [] Puffer, Int32-Offset, Int32-Größe, SocketFlags socketFlags)

at System.Net.Sockets.NetworkStream.Read (Byte [] Puffer, Int32-Offset, Int32-s ize)

--- Ende der inneren Ausnahmestapelverfolgung ---

at System.Net.Sockets.NetworkStream.Read (Byte [] Puffer, Int32-Offset, Int32-s ize)

at TCP_Server.Program.Main (String [] args)

Clientcode (Dies ist innerhalb der Schleife):

            try
            {
                Int32 port = 13777;
                using (TcpClient client = new TcpClient(ip, port))
                using (NetworkStream stream = client.GetStream())
                {
                    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                    var data = GenerateData(size);

                    sw.Start();
                    // Send the message to the connected TcpServer. 
                    stream.Write(data, 0, data.Length);

                    // Buffer to store the response bytes.
                    data = new Byte[size];

                    // Read the first batch of the TcpServer response bytes.
                    Int32 bytes = stream.Read(data, 0, data.Length);

                    sw.Stop();
                    Console.WriteLine(i + ": Done transporting " + size + " bytes to and from " + ip + " time: " +
                                      sw.ElapsedMilliseconds + " ms");
                    // Close everything.
                    stream.Close();
                    client.Close();
                }

            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine("ArgumentNullException: {0}", e);
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }

            sw.Reset();

Servercode: 

            Byte[] bytes = new Byte[size];

            // Enter the listening loop. 
            for (int i = 0; i < numberOfPackages; i++)
            {
                using (TcpClient client = server.AcceptTcpClient())
                using (NetworkStream stream = client.GetStream())
                {
                    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                    // Loop to receive all the data sent by the client. 
                    while ((stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Send back a response.
                        stream.Write(bytes, 0, size);

                    }
                    client.GetStream().Close();
                    client.Close();
                }


                Console.WriteLine("Receive data size " + size);

            }

Ich habe Wireshark verwendet, um die gesendeten TCP-Pakete zu überwachen, und festgestellt, dass ein TCP RST vom Client an den Server gesendet wird, bevor das Programm abstürzt. Ich gehe also davon aus, dass das Problem darin besteht, dass das RST nicht korrekt gehandhabt wird. Es gibt keine Firewall zwischen dem Client und dem Host, sodass das Problem nicht besteht.

Die Wireshark-Dateien für den Client und den Server finden Sie hier: https://www.dropbox.com/sh/ctl2chq3y2c20n7/AACgIJ8IRiclqnyOyw8sqd9La?dl=0

Entweder muss ich die TCP RST loswerden oder ich brauche meinen Server, um irgendwie damit umzugehen und nicht abstürzen.

Ich habe versucht, längere Wartezeiten zu verwenden, aber es hilft nicht. Wenn die Daten unter 5840 Bytes liegen, bekomme ich keine Abstürze, was ich weiß.

Anregungen oder Ideen?

BEARBEITEN: Dank der Antworten habe ich es mit den folgenden Änderungen gemacht:

Server:

// Loop to receive all the data sent by the client.
int k = 0;
while (k < size)
{
   int bytesRead = stream.Read(bytes, 0, bytes.Length);
   k += bytesRead;
}
// Send back a response.
stream.Write(bytes, 0, size);

Und das gleiche beim Empfang auf der Clientseite. Da ich zuerst alle Daten senden und dann den Server reagieren lassen möchte, funktioniert dies für meine Anwendung.

11
TobiasW

Zwei Probleme, die ich sehe:

  1. Sie gehen davon aus, dass ein Lesevorgang für size-Bytes tatsächlich size-Bytes liest. Es tut nicht. TCP ist ein Streaming-Protokoll. Ein Lesevorgang liest mindestens ein Byte. Das ist die einzige Garantie.
  2. Ihr Code wird zufällig blockiert. Der Client schreibt Daten auf den Server. Der Server gibt es zurück. Der Client kann jedoch erst lesen, wenn er alles geschrieben hat. Wenn mehr geschrieben wird, als die Netzwerkpuffer aufnehmen können, führt dies zu einem Deadlock. Der Client muss gleichzeitig lesen und schreiben. Möglicherweise benötigen Sie einen anderen Thread/Task zum Zurücklesen der Daten. Ein gutes Muster, um dieses Problem zu lösen, wäre, eine Writer-Task, eine Reader-Task und Task.WhenAll/WaitAll zu starten, um sie wieder anzuschließen.

Ich bin nicht sicher, unter welchen Umständen ein TCP -Stack einen RST senden würde. Möglicherweise liegt das Deadlock für ein Timeout.

Sie schlucken keine Ausnahmen, richtig?

Normalerweise wird beim Schließen einer Verbindung ein ordnungsgemäßes Herunterfahren im Hintergrund ausgeführt. Aber ich bin nicht sicher, was passiert, wenn die andere Seite zu diesem Zeitpunkt noch schreibt. Möglicherweise lautet die Antwort, dass vom Empfänger der Schreibvorgänge eine RST generiert wird. Sicher würde die Spezifikation von TCP diese Frage beantworten. Wenn diese Antwort vertrauenswürdig sein soll, dann würde ein Herunterfahren (Lesen)/Schließen gefolgt von einem eingehenden Schreibvorgang die Verbindung RST rST.

Beheben Sie beide Probleme und berichten Sie mit Ihren Ergebnissen.

8
usr

Ich habe das gleiche Problem mit zunehmendem Cache-Limit von iis root-Eintrag gelöst. Sie können das Caching auch deaktivieren. Ich hoffe es hilft.

0
user2504655

Wir hatten dieses Problem bei der Verwendung von zufälligen HttpClient-Fehlern wie

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote Host.
 ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote Host

oder

 ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.

Problem bei der Benachrichtigung über explizite Überlastung oder ECN im TCP -Stack. Dies wird auch als ECN-Fähigkeit bezeichnet. Explicit Congestion Notification ist eine Erweiterung des Internet Protocol und des Transmission Control Protocol und ist in RFC 3168 definiert. ECN ermöglicht die End-to-End-Benachrichtigung über Netzwerkstaus, ohne Pakete zu verlieren. Wenn die ECN-Funktion aktiviert ist, können Sie sie deaktivieren:

netsh interface tcp set global ecncapability=disabled

Ein Neustart ist nicht erforderlich.

0
Daniil Sokolyuk

Ich bin kein Experte, aber Sie denken nicht, dass das Aufrufen von stream.Close () auf dem Client den Stream schließt, während der Server immer noch versucht zu schreiben 

// Send back a response.
stream.Write(bytes, 0, size);

Möglicherweise möchten Sie auch einige Daten als Ende angeben, damit der Server das Lesen kennt und aufhört.

0
user2527768