2016-09-13 5 views
0

Erster Hintergrund. Ich habe eine Kamera, mit der meine App über ein Ethernetkabel verbunden ist, und sie führt Operationen basierend auf Befehlen aus, die ich sende und antwortet mit Befehlen zurück.Schnelle Paketverarbeitung aus Stream

Wenn ich den Kameraauslösebefehl als Beispiel nehme. Die Kamera wird ein Bild machen, wenn ich es 'T1' sende. Alle Befehle verwenden, um eine Start- und Ziel char den Beginn und das Ende des Pakets zu markieren, so die volle Paket Ich mag dieses

(char) 0x02T1 (char) 0x03

mit (char) 0x02 als Start aussehen senden von Paket und (char) 0x03 als das Ende der Packung.

Die Kamera nimmt dann ein Bild auf und sendet den gleichen Befehl zurück, um zu sagen, dass es erledigt ist. Sie können die Kamera auch so einstellen, dass sie Daten zurücksendet, wenn sie das Bild aufgenommen hat. In meinem Fall habe ich die Kamera inspizieren ein paar Bereiche und ich möchte einige Werte von der Inspektion.

So ist die Rückkehr der Kamera wäre so etwas wie ‚T1‘ und dann sagen ‚1,1,500,20,300‘

On für das Problem. Ich benutze eine TcpClient und eine NetworkStream für die Kommunikation, aber ich habe Probleme mit der Verarbeitung der Pakete auf der Empfängerseite. Ich habe verschiedene Methoden ausprobiert, aber sie scheinen langsam zu sein oder garantieren nicht, dass ich alle Daten bekomme.

Zuerst brauche ich etwas, das alle Daten liest und sicherstellen, dass ich alle Daten habe.

Zweitens brauche ich etwas, das die Daten verarbeiten und in Pakete aufteilen kann und dies so schnell wie möglich tun.

Dies ist nur eine Methode, die ich versucht habe und volle Anerkennung geht an die Person, die die StreamReaderExtensions gemacht hat. Ich bin sicher, ich habe es irgendwo hier gefunden.

internal static class StreamReaderExtensions 
{ 
    public static IEnumerable<string> ReadUntil(this StreamReader reader, string delimiter) 
    { 
     List<char> buffer = new List<char>(); 
     CircularBuffer<char> delim_buffer = new CircularBuffer<char>(delimiter.Length); 

     while (reader.Peek() >= 0) 
     { 
      char c = (char)reader.Read(); 
      delim_buffer.Enqueue(c); 
      if (delim_buffer.ToString() == delimiter) 
      { 
       if (buffer.Count > 0) 
       { 
        yield return new String(buffer.ToArray()); 
        buffer.Clear(); 
       } 
       continue; 
      } 
      buffer.Add(c); 
     } 
    } 

    private class CircularBuffer<T> : Queue<T> 
    { 
     private int _capacity; 

     public CircularBuffer(int capacity) 
      : base(capacity) 
     { 
      _capacity = capacity; 
     } 

     new public void Enqueue(T item) 
     { 
      if (base.Count == _capacity) 
      { 
       base.Dequeue(); 
      } 
      base.Enqueue(item); 
     } 

     public override string ToString() 
     { 
      List<String> items = new List<string>(); 
      foreach (var x in this) 
      { 
       items.Add(x.ToString()); 
      }; 
      return String.Join("", items); 
     } 
    } 
} 

und meine Prozessmethode. _stream ist TcpClient.GetStream()

public static class Constants 
{ 
    public const char StartOfPacket = (char)0x02; 
    public const char EndOfPacket = (char)0x03; 
} 

private IEnumerable<string> ProcessResponse() 
{ 
    var streamReader = new StreamReader(_stream); 
    var packets = streamReader.ReadUntil(new string(new char[] {Constants.EndOfPacket})); 
    return packets; 
} 
+0

Sie sollten pro Char lesen. Lies einfach einen großen Block und überprüfe die erhaltene Größe. Analysieren Sie den Block, bis Sie das Trennzeichen gefunden haben, und entfernen Sie den analysierten Block. Wiederholen Sie dies, bis Sie halbe Pakete haben. –

+0

@ JeroenvanLangen halbe Pakete? – Gaz83

+0

könnte eine Nachricht in mehrere Pakete aufgeteilt werden. Dies liegt daran, dass es sich um einen Stream anstelle eines Datagramms handelt. Wenn Sie nur 1 Char zu der Zeit erhalten, ist es immer in mehrere geteilt, –

Antwort

0

ich einige Pseudo-Code gemacht für, ich habe es nicht getestet haben, aber es könnte Ihnen eine Richtung geben. Dies ist nicht statisch sein kann

char[] _buffer = new char[4 * 1024 * 1024]; 
int currentPosition; 

public bool ReadNext(StreamReader reader, char delimiter, out string value) 
{ 
    // read as many chars from the stream. 
    int charsRead = reader.ReadBlock(_buffer, currentPosition, _buffer.Length - currentPosition); 

    // keep track of the current position. 
    currentPosition += charsRead; 

    // find the first delimiter. 
    for (int i = 0; i < currentPosition; i++) 
    { 
     if (_buffer[i] == delimiter) 
     { 
      // a complete packet was found, copy it to a string. 
      value = new string(_buffer, 0, i); 
      // move the rest of the data back to the start of the buffer. 
      Array.Copy(_buffer, i, _buffer, 0, _buffer.Length - i); 
      // decrease the current position also. 
      currentPosition -= i; 
      // return true because you have data. 
      return true; 
     } 
    } 

    // no complete packet was found. 
    value = String.Empty; 
    return false; 
} 

Verbrauch:

string data; 

while(true) 
{ 
    if(ReadNext(reader, (char)0x03, out data)) 
     MessageBox.Show(data); 
} 

Wie ich schon sagte ungetestet, das nur ein Brainfart ist ... Sie müssen möglicherweise die Überprüfung der hinzufügen der Beginn des Pakets.

+0

Danke dafür. Ich werde es gut durchsehen und ausprobieren. – Gaz83

+0

Ich bin gerade dabei, das auszuprobieren und aus irgendeinem Grund bekomme ich ein "System.IO.Ausnahme "beim Ausführen des' ReadBlocks ". Innere Ausnahme sagt" Ein Verbindungsversuch ist fehlgeschlagen, weil der verbundene Teilnehmer nach einer bestimmten Zeit nicht korrekt reagiert hat. " Schreiben in den gleichen Stream funktioniert problemlos. – Gaz83

+0

Ist die Verbindung? von einer Firewall geblockt? (andere Seite) –