2017-01-11 1 views
-1

Ich schreibe einen kleinen HttpServer, irgendwann stoße ich auf ein Problem mit fehlenden POST Daten.C# IInputStream fehlendes segmentiertes TCP-Paket

Durch die Verwendung von Wireshark entdeckte ich, dass die Header in two segments aufgeteilt ist.

Wireshark Reassembled TCP Segments

bekomme ich nur das erste Segment (636 Bytes), die zweite (POST Daten in diesem Fall) wird völlig verloren.

Hier ist eine der entsprechende C# -Code

string requestHeaderString = ""; 
StreamSocket socketStream = args.Socket; 

IInputStream inputStream = socketStream.InputStream; 
byte[] data = new byte[BufferSize]; 
IBuffer buffer = data.AsBuffer(); 

try 
{ 
    await inputStream.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial); 

    // This is where things go missing, buffer.ToArray() should be 678 Bytes long, 
    // so Segment 1 (636 Bytes) and Segment 2 (42 Bytes) combined. 
    // But is only 636 Bytes long, so just the first Segment?! 
    requestHeaderString += Encoding.UTF8.GetString(buffer.ToArray()); 
} 
catch (Exception e) 
{ 
    Debug.WriteLine("inputStream is not readable" + e.StackTrace); 
    return; 
} 

Dieser Code in einem Teil des StreamSocketListenerConnectionReceivedEvent ist.

Muss ich die TCP-Segmente manuell zusammensetzen, sollte das nicht der System-TCP-Stack tun?

Danke, David

+1

Sie ignorieren den von 'recv()' (oder seinem Wrapper 'Read()') zurückgegebenen Integer-Wert, der das erste Problem ist, dem Menschen beim Schreiben ihres eigenen Codes mit Sockets begegnen. Hast du versucht zu suchen? Nachdem Sie dieses Problem behoben haben, möchten Sie vielleicht http://stackoverflow.com/questions/27228343/what-are-the-consequences-of-not- including-a-content-length-header-in-a-server lesen -r – CodeCaster

+0

_Muss ich die TCP-Segmente manuell neu zusammensetzen, sollte das nicht der System-TCP-Stack tun? _ Ja, Sie müssen die Teile neu zusammensetzen. TCP garantiert einfach, dass die ** Bestellung ** der Teile korrekt ist. Es macht keine Versprechen darüber, wie diese Daten ankommen werden; es könnte in kleinere Stücke zerlegt werden, oder mehrere "Sends" könnten zusammengestückelt ankommen. Es liegt an Ihnen, dem Programmierer zu wissen, wann eine vollständige "Nachricht" angekommen ist, und diese aus Ihrem eigenen Puffer zu extrahieren. Sie ignorieren auch, wie viele Bytes zurückgegeben wurden, was bedeutet, dass der Aufruf von GetString() möglicherweise Müll zurückgibt. –

+2

Eine Reihe von Problemen. Hauptsächlich ignorieren Sie den Rückgabewert, von dem Sie eigentlich Ihre Daten erhalten sollten. Die [Dokumentation] (https://msdn.microsoft.com/library/windows/apps/br241719) könnte nicht klarer darüber sein. * "Lesen Sie immer Daten aus dem Puffer, der in IAsyncOperationWithProgress (IBuffer, UInt32) zurückgegeben wird.Gehen Sie nicht davon aus, dass der Eingabepuffer die Daten enthält. Abhängig von der Implementierung können die gelesenen Daten in den Eingabepuffer gelegt werden, oder sie könnten in einem anderen Puffer zurückgegeben werden. "* Sie sollten versuchen, es zu lesen. – spender

Antwort

2

Das Problem ist, die Systeme TCP-Stack den TCP-Stream wie jeder andere Strom behandelt. Sie erhalten keine "Nachrichten" mit Streams, Sie erhalten nur einen Strom von Bytes.

Die empfangende Seite hat keine Möglichkeit zu sagen, wann eine "Nachricht" endet und wo die nächste beginnt, ohne dass Sie etwas darüber sagen. Sie müssen message framing über TCP implementieren, dann müssen Sie auf Ihrer Empfangsseite wiederholt Receive aufrufen, bis Sie genügend Bytes erhalten haben, um eine vollständige Nachricht zu bilden (das wird die Verwendung des int des Empfangsaufrufs verwenden, um zu sehen, wie viele Bytes verarbeitet wurden) .

Wichtiger Hinweis: Wenn Sie nicht wissen, wie viele Bytes Sie insgesamt erwarten, z. B. Nachrichtenrahmung mithilfe von '\0', um Nachrichten zu trennen, erhalten Sie möglicherweise das Ende einer Nachricht und den Beginn der Nachricht als nächstes in einem einzigen Empfangsanruf. Sie müssen mit dieser Situation umgehen.

EDIT: Sorry, ich übersprang die Tatsache, dass Sie HTTP lesen. Sie müssen dem Protokoll von HTTP folgen. Sie müssen Daten einlesen, bis Sie das Muster \r\n\r\n sehen, sobald Sie erhalten, dass Sie die Kopfzeile analysieren und entschlüsseln müssen, wie viel Daten im Inhaltsabschnitt der HTTP-Nachricht sind, dann wiederholen Sie wiederholt gelesen, bis Sie die Anzahl der benötigten Bytes gelesen haben.

+1

Ja, HTTPs Nachrichtenrahmen ist ein * riesiger * Schmerz, um richtig zu machen.Ich empfehle die Verwendung von ASP.NET Core oder [WebListener] (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/weblistener) wenn [einer der schnellsten Stacks ] (https://www.ageofascent.com/2016/02/18/asp-net-core-exeeds-1-15-million-requests-12-6-gbps/) ist nicht schnell genug ... –