Was ist ein funktionierendes Beispiel mit Paketfragmentierung in C # Umgang aussehen, wenn die * Ende * Begin-Methode verwenden?

StackOverflow https://stackoverflow.com/questions/1129000

Frage

Nachdem genügend Spiel mit asynchroner Socket-Programmierung bemerkte ich, dass der Server Chunked Nutzlasten wurde empfangen (dh mehr als eine vollständige Nutzlast in dem gleichen Puffer sitzen). So kam ich mit dem folgenden:

if (bytes_to_read > 0)
{
    while (bytes_to_read > 0)

        // Get payload size as int.

        // Get payload in byte format.

        // Do something with payload.

        // Decrease the amount of bytes to read.
    }

    // Wait for more data.
}

Und dann bemerkte ich Paketzerteilung (dh: was ich dachte, waren komplette Nutzlasten chunked zusammen war nicht immer so), die den vorherigen Code ähnlich wie folgt geändert:

if (bytes_to_read > 0)
{
    while (bytes_to_read > 0)
    {
        // Get payload size as int.

        // Check if the payload size is less than or equal to the amount of bytes left to read.
        if (payload_size <= bytes_to_read)
        {
            // Get payload in byte format.

            // Do something with payload.

            // Decrease the amount of bytes to read.
        }
        else
        {
            // We received a fragmented payload.
            break;
        }
    }

    if (bytes_to_read == 0)
    {
        // Wait for more data.
    }
    else if (bytes_to_read > 0)
    {
        // Wait for more data where we left off. ***
    }
    else
    {
        // Something awful happened.
    }
}

*** Ich weiß nicht einmal, wie um dies zu realisieren und mag Code für sie sehen. Ich hatte eine Idee, dass er beteiligt Kopieren die in abgeschlossene Nutzlast an den Anfang des Puffers und dann von dort Abholung.

Der Pseudocode I enthalten ist, basierend auf dem Begin * Ende * Methode verwende ich (ich bin mir bewusst, dass ich die * Async Reihe von Methoden, die hier gefunden werden, mit -> http://msdn.microsoft.com/en-us/library/system.net.sockets. socketasynceventargs.aspx <- aber ich denke, meine allgemeine Frage immer noch gilt)

.

Ich suche die Antworten auf zwei Fragen - nämlich:

  1. Ist dieser Ansatz richtig oder bin ich etwas fehlt?
  2. Wie sieht ein funktionierendes Beispiel für Umgang mit Paketfragmentierung in C # aus?

EDIT:. Ich bin mit Raw Sockets

Vielen Dank im Voraus für Ihre Hilfe.

EDIT:. John Saunders und Greg Hewgill haben den Punkt der Behandlung von Daten als Strom gebracht, aber das macht bietet mir nicht mit einem konkreten Beispiel, wie mit der letzten chunked Nutzlast manchmal behandeln fragmentiert sein

EDIT: Ich habe Jon Skeet Antwort lesen hier die im Grunde auf der gleichen Linie wie die anderen Antworten, die ich gesehen habe, aber es hat mir nicht viel helfen, wie ich schon bekommen, was ich zu tun haben, aber nicht, wie es zu tun.

EDIT: Um zu erarbeiten, was ich durch Fragmentierung bedeutet, sollten Sie Folgendes beachten die Puffer erhalten:

  • 224TEST3foo3bar
  • 224TEST3foo3bar224TEST3foo3bar
  • 224TEST3foo3bar224TEST3foo
  • 3bar224TEST3foo3bar

EDIT: Ich fand diese und this , die mich führen hier . Vadym Stetsiak fast alles geklärt hat (sein war eine der Antworten, denn ich war auf der Suche).

War es hilfreich?

Lösung 2

Wenn Sie es selbst zu tun haben, kann es wie so durchgeführt werden ( Referenz hier ):

/// 
/// Server state holds current state of the client socket
///
class AsyncServerState
{
   public byte[] Buffer = new byte[512]; //buffer for network i/o
   public int DataSize = 0; //data size to be received by the server

   //flag that indicates whether prefix was received
   public bool DataSizeReceived = false;

   public MemoryStream Data = new MemoryStream(); //place where data is stored
   public SocketAsyncEventArgs ReadEventArgs = new SocketAsyncEventArgs();
   public Socket Client;
}

/// 
/// Implements server receive logic
/// 
private void ProcessReceive(SocketAsyncEventArgs e)
{
    //single message can be received using several receive operation
    AsyncServerState state = e.UserToken as AsyncServerState;

    if (e.BytesTransferred <= 0 || e.SocketError != SocketError.Success)
    {
        CloseConnection(e);
    }

    int dataRead = e.BytesTransferred;
    int dataOffset = 0;
    int restOfData = 0;

    while (dataRead > 0)
    {
        if (!state.DataSizeReceived)
        {
            //there is already some data in the buffer
            if (state.Data.Length > 0)
            {
                restOfData = PrefixSize - (int)state.Data.Length;
                state.Data.Write(state.Buffer, dataOffset, restOfData);
                dataRead -= restOfData;
                dataOffset += restOfData;
            }
            else if (dataRead >= PrefixSize)
            {   //store whole data size prefix
                state.Data.Write(state.Buffer, dataOffset, PrefixSize);
                dataRead -= PrefixSize;
                dataOffset += PrefixSize;
            }
            else
            {   // store only part of the size prefix
                state.Data.Write(state.Buffer, dataOffset, dataRead);
                dataOffset += dataRead;
                dataRead = 0;
            }

            if (state.Data.Length == PrefixSize)
            {   //we received data size prefix
                state.DataSize = BitConverter.ToInt32(state.Data.GetBuffer(), 0);
                state.DataSizeReceived = true;

                state.Data.Position = 0;
                state.Data.SetLength(0);
            }
            else
            {   //we received just part of the headers information
                //issue another read
                if (!state.Client.ReceiveAsync(state.ReadEventArgs))
                    ProcessReceive(state.ReadEventArgs);
                    return;
            }
        }

        //at this point we know the size of the pending data
        if ((state.Data.Length + dataRead) >= state.DataSize)
        {   //we have all the data for this message

            restOfData = state.DataSize - (int)state.Data.Length;

            state.Data.Write(state.Buffer, dataOffset, restOfData);
            Console.WriteLine("Data message received. Size: {0}",
                                  state.DataSize);

            dataOffset += restOfData;
            dataRead -= restOfData;

            state.Data.SetLength(0);
            state.Data.Position = 0;
            state.DataSizeReceived = false;
            state.DataSize = 0;

            if (dataRead == 0)
            {
                if (!state.Client.ReceiveAsync(state.ReadEventArgs))
                    ProcessReceive(state.ReadEventArgs);
                    return;
            }
            else
                continue;
        }
        else
        {   //there is still data pending, store what we've
            //received and issue another BeginReceive
            state.Data.Write(state.Buffer, dataOffset, dataRead);

            if (!state.Client.ReceiveAsync(state.ReadEventArgs))
                ProcessReceive(state.ReadEventArgs);

            dataRead = 0;
        }
    }
}

Ich habe es nicht genau auf diese Weise selbst, aber es hilft.

Andere Tipps

Dies kann oder kann nicht alles mit der Fragmentierung zu tun hat.

In der Regel wird die Buchse Sie so viele Bytes zu einer Zeit vergehen, da es wie fühlt. Ihre Aufgabe ist es zu wissen, wie viele Bytes in Ihrer Gesamtbotschaft ist, und sie alle zu lesen. Denken Sie Schleife, bis Sie haben alle Bytes, die Sie benötigen, oder bis es eine Ausnahme.


Der folgende Code ist jetzt nicht getestet. Ich dachte, ich würde es schreiben, bevor die Server-Seite davon zu schreiben und beide testen.

private static string ReceiveMessage(Socket socket)
{
    const int BUFFER_SIZE = 1024;
    var inputBuffer = new byte[BUFFER_SIZE];
    var offset = 0;
    var bytesReceived = socket.Receive(
        inputBuffer, offset, BUFFER_SIZE - offset, SocketFlags.None);
    if (bytesReceived < 2)
    {
        throw new InvalidOperationException("Receive error");
    }

    var inputMessageLength = inputBuffer[0]*256 + inputBuffer[1];
    offset += bytesReceived;
    var totalBytesReceived = bytesReceived;
    while (bytesReceived > 0 &&
           totalBytesReceived < inputMessageLength + 2)
    {
        bytesReceived = socket.Receive(
            inputBuffer, offset, BUFFER_SIZE - offset, SocketFlags.None);
        offset += bytesReceived;
        totalBytesReceived += bytesReceived;
    }

    return Encoding.UTF8.GetString(
        inputBuffer, 2, totalBytesReceived - 2);
}

Beachten Sie, dass der Empfang der Nachrichtenlänge ist falsch. Die Socket-Schicht könnte es ein Byte zu einem Zeitpunkt, mir geben. Ich werde das als Teil eines Refactoring zu überdenken, die die Zählung in einen separaten Zwei-Byte-Puffer empfangen werden, und die Schleife in ein einziges do / while ändern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top