2009-03-04 6 views
1

So empfange ich Daten über einen Socket mit einem Puffer (Byte []) der Größe 1024, und ich möchte die Lesevorgänge zusammen zu bilden, um das gesamte Paket für den Fall, dass sie größer als 1024 Bytes sind. Ich wählte eine Liste das gesamte Paket zu speichern, und das, was ich tun möchte, ist jeden Puffer, um es zu lesen hinzufügen, wie es kommt Ich will machen würde.Wie kann ich Byte [] Puffer in eine Liste <byte> einfügen?

List.AddRange(Buffer); 

Aber in dem Fall, dass der Puffer isn Wenn ein leeres Byte voll ist, wird es bis zum Ende gepolstert. Natürlich möchte ich nur einen bestimmten Bereich von Bytes zur Liste hinzufügen, aber es gibt keine solche Methode. Ich könnte immer ein temporäres Byte-Array von genau der Anzahl von Bytes erstellen, die empfangen wurden, und dann AddRange() verwenden und das gewünschte Ergebnis erhalten, aber es erscheint mir nur dumm. Ganz zu schweigen davon, dass es bei jedem Lesen von Daten ein Array wegwerfen würde, was für die Leistung auf einem skalierbaren Mehrbenutzer-Server nicht gut wäre.

Gibt es eine Möglichkeit, dies mit einer Liste zu tun? Oder gibt es eine andere Datenstruktur, die ich verwenden kann?

Antwort

6

Wenn Sie mit C# 3.5 (LINQ)

list.AddRange(buffer.Take(count)); 
0

Ich weiß nicht, welches Protokoll Sie verwenden, oder wenn Sie ein benutzerdefiniertes Protokoll implementieren, aber wenn Sie die Größe identifizieren, können Sie Buffer.BlockCopy verwenden, um die Bytes direkt in ein neues Array zu kopieren, um es Ihrer Liste hinzuzufügen.

Es ist schwer, prägnanter zu sein, wenn Sie keine Besonderheiten haben.

+0

Ich möchte sie nicht in ein neues Array kopieren, das ist, was ich versuche zu vermeiden. – ryeguy

+0

Verwenden Sie dann Take, wenn Sie 3.5 zur Verfügung haben, indem Sie die genaue Größe der empfangenen Bytes kopieren, wie es Joel vorgeschlagen hat. –

1

Für .Net3.5 können Sie die Erweiterungsmethode .Take() verwenden, um nur die tatsächliche Anzahl der empfangenen Bytes zurückzugeben.

+0

Will .Take() Box unter der Haube? –

+0

Sollte nicht: es ist generisch (wirklich Take ()) –

0

Sie können Ihre eigene IEnumerable-Implementierung implementieren, die nur die gewünschten Bytes aus dem Array abruft. Dann könnten Sie folgendes tun:

List.AddRange (neuer BufferEnumerator (Buffer));

bearbeiten

Sie können auch aussehen:

neue System.ArraySegment (Puffer, 0, numBytesRecieved)

Ich bin nicht positiv, wenn ich Array funktionieren würde, erinnern einige Nachteile davon zu lesen aber erinnere mich nicht an die Besonderheiten.

0

Sie können Array.Copy() und nur Arrays verwenden, um Ihre Zielpuffer aufbauen:

byte[] recvBuffer = new byte[1024]; 
byte[] message = new byte[0]; 
int nReaded; 

while ((nReaded = ....Read(recvBuffer, 1024) > 0) 
{ 
    byte[] tmp = new byte[message.Length + nReaded]; 
    Buffer.BlockCopy(message, 0, tmp, 0, message.Length); 
    Buffer.BlockCopy(recvBuffer, 0, tmp, message.Length, nReaded); 
    message = tmp; 
} 

EDIT: Ersetzte Array.Copy() durch Buffer.BlockCopy() wie von Quintin Robinson in den Kommentaren vorgeschlagen.

+0

Sie möchten möglicherweise vermeiden, Array.Copy verwenden, wenn Sie nur mit Bytes zu tun, wie es Box wird, stattdessen können Sie Buffer.BlockCopy verwenden, die die Bytes direkt kopieren. –

+0

Lesen Sie die Frage noch einmal: All das Kopieren ist genau das, was das OP zu vermeiden versucht. –

+0

@Joel Coehoorn: Er wollte gerade kein temporäres Array erstellen, um die Liste .AddRange() aufzurufen. Aber in meiner Lösung braucht er keine nutzlosen zusätzlichen Arrays (tmp ist nicht nutzlos, weil es das neue Nachrichtenarray bekommt!) – mmmmmmmm

2

Haben Sie eigentlich brauchen das Ergebnis zu einem List<byte>? Was wirst du danach machen? Wenn Sie wirklich nur eine IEnumerable<byte> brauchen würde ich vorschlagen, so etwas wie dies zu schaffen:

using System; 
using System.Collections; 
using System.Collections.Generic; 

public class ArraySegmentConcatenator<T> : IEnumerable<T> 
{ 
    private readonly List<ArraySegment<T>> segments = 
     new List<ArraySegment<T>>(); 

    public IEnumerator<T> GetEnumerator() 
    { 
     foreach (ArraySegment<T> segment in segments) 
     { 
      for (int i=0; i < segment.Count; i++) 
      { 
       yield return segment.Array[i+segment.Offset]; 
      } 
     } 
    } 

    public void Add(ArraySegment<T> segment) 
    { 
     segments.Add(segment); 
    } 

    public void Add(T[] array) 
    { 
     segments.Add(new ArraySegment<T>(array)); 
    } 

    public void Add(T[] array, int count) 
    { 
     segments.Add(new ArraySegment<T>(array, 0, count)); 
    } 

    public void Add(T[] array, int offset, int count) 
    { 
     segments.Add(new ArraySegment<T>(array, offset, count)); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Dann können Sie fügen Sie einfach die entsprechenden Segmente jedes Mal.Natürlich könnte man am Ende viel verschwendeten Speicher haben, und man müsste vorsichtig sein, jedes Mal einen neuen Puffer zu erstellen (anstatt das Original erneut zu lesen), aber es wäre auf andere Weise effizient.

Verwandte Themen