Laden...

Schleife um bestimmte Anzahl an Bytes zu kopieren

Erstellt von Bartando77 vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.460 Views
Thema geschlossen
B
Bartando77 Themenstarter:in
14 Beiträge seit 2010
vor 13 Jahren
Schleife um bestimmte Anzahl an Bytes zu kopieren

Hallo Jungs,

ich versuche den ganzen Tag eine Schleife aufzubauen die mir bestimmte Stücke aus einem byte kopiert und in eine Methode weitergibt. Irgendwie fehlt mir aber das Denken oder sonst was , jedenfalls komm ich nicht drauf und das nervt mich weils eigentlich einfach ist 😦

Also ich hab ein Byte-Array **Daten[] **9000byte groß, dort sind von einer anderen Methode drei bis vier 200 bis 1000byte lange "DatenPakete" reingeschrieben worden.

Ich erhalte die Anzahl der erhaltenenn Bytes z.b 3400bytes.

in diesen 3400 bytes stecken 4 Pakete mit 3x 1000byte und einmal 400byte.

Jedes Paket hat in den ersten 2 bytes (Int16) eine Information wie lang das Paket ist z.b "1000" für 1000 bytes.

Jetzt hab ich eine Methode

Video.DataConvert(byte[] PaketDatabytes, int DataPaketLength);

Es sollen jetzt immer die einzelnen BytePakete übergeben werden bis das ByteArray keine Pakete mehr hat.

Wie kann ich das "Schleifilisieren"?

Ich hab zwar die Idee aber ich kann es bei besten willen nicht umsetzen daher würde ich euch vielleicht bitten mir ein wenig zu helfen.

Meine Idee

while(DatenEnde == AnzahlErhalteneBytes)  //Also wenn das Ende des letzten Pakets den gleichen Wert hat wie die Anzahl der Empfangenen Bytes dann fertig.
{
/*
Meine Schleifen Idee die ich nicht umsetzen kann:

1. lese die ersten zwei Byte aus und wandle in int (LängenInformation des DatenPakets).

2. Kopiere mit BufferBlock.Copy das Array von Anfang [0] bis Ende  (Ende durch Längeninformation bspw. [1000]) in das ByteArray Temp[Länge = Längeninformation = 1000]

3.Gebe es an Methode weiter  
\*/

Video.DataConvert(Temp, Temp.Length);

/*
4. Nun kopiere das nächste Paket in Temp,  also Ab byte 1000  bis Paketlänge  (hier wieder die ersten zwei byte auslesen und in int  wandeln um die Paketlängeninformation zu erhalten)  und gebe das Array der Methode weiter:

\*/

Video.DataConvert(Temp, Temp.Length);

/*
5. jetzt das letzte Paket holen , also wieder ab Ende des letzten Pakets bis Ende der Längeninformation in Temp kopieren und der Methode weiter geben 

6. Wenn dies jetzt das letzte Paket war, dann entspricht der Wert für das Ende des letzten Pakets also bspw. Wert 3400 gleich der Anzahl der erhaltenen Bytes also das Ende wurde erreicht und es gibt keine weiteren Daten mehr. => schleife beendet.

/*
}
 

Ich komm einfach nicht dahinter wie ich das schreiben kann was ich bisher geschrieben habe war Bockmist.
Für Ratschläge und hilfen würde ich mich freuen.

mfg
Berti

3.430 Beiträge seit 2007
vor 13 Jahren

Hallo Bartando77,

du denkst da nur etwas zu kompliziert 😉

Eigentlich müsste es reichen wenn du einfach eine Schleife macht welche so lange läuft bis der Array leer ist.
Jedes mal rufst du eine Methode auf die in den ersten beiden Bytes die Länge des Pakets ausliest.
Dann wird diese Methode das ganze Paket auslesen und aus dem Array entfernen (abschneiden) und dieses wieder an die Methode (die mit der Schleife) zurückgeben.

Welche dann checkt ob noch elemente im Array sind. Wenn ja, dann wird die ganze Sache nochmal gemacht.

Du musst den Array eigentlich auch nicht cutten.
Es reicht wenn die DataConvert-Methode einen int mit dem aktuellen Index zurückgibt. Wenn dieser kleiner als die Länge des Arrays (-1) ist dann einfach fortsetzen.

Gruss
Michael

B
Bartando77 Themenstarter:in
14 Beiträge seit 2010
vor 13 Jahren

ok,

wie kann ich denn prüfen wann das array leer ist ? du meinst das Array hat hat die Length = 0 ?

Aus dem Array Abschneiden damit meinst du das ich mit Bufferblock copy ein neues array erstelle oder wie?

mfg
Berti

3.430 Beiträge seit 2007
vor 13 Jahren

Hallo,

das Abschneiden ist eigentlich nicht die optimale Lösung, da es nicht wirklich performant ist.
Hab ich nur mal vorhin am Rande erwähnt aber nicht wirklich weit gedacht 😉

Besser ist wenn deine Methode einfach einen int zurückgibt und diesen dann beim nächsten Aufruf wieder bekommt.

Hier ein kleiner Pseudocode


private void BlaBla()
{
    byte[] data;
    int pos = 0;
    while(pos<data.Length)
    {
        pos = GetPacket(data,pos);
    }
}

private int GetPacket(byte[] data, int startIndex)
{
     //Daten auslesen und irgendwo hinspeichern (wo auch immer du willst)
     return startIndex + LaengeDerAusgelesenenDaten;
}

So in etwa habe ich das gemeint.

Du kannst die GetPacket-Methode auch direkt in die Schleife schreiben (wie du willst).
Da gibt es bestimmt Massenweise Lösung aber das ist IMHO eine die recht einfach zu verstehen ist.

Gruss
Michael

B
Bartando77 Themenstarter:in
14 Beiträge seit 2010
vor 13 Jahren

Hi,

ich hab das jetzt gemacht wie du meintest hier ist mein Code:

Jetzt ist folgendes Merkwürdig, wenn ich die Pakete ausgebe dann erhalte ich immer die gleichen Inhalte aber auf die richtige größen zugeschnitten.

wenn ich die TelegrammLängeninfo zur kontrolle auslesen will mit BitConverter dann erhalte ich die auch richtig. 10,8,14

aber wenn ihc jetzt das Paket als solches ausgebe sehe ich immer nur die inhalte des ersten paketes.

wie kann das sein? wo ist da mein fehler ? wenn es doch immer das gleiche paket wäre wie kann er dann die Paketinformationen der drei pakete erhalten ha ha?


using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Threading;


namespace schleifentest
{
    class Program
    {
        static void Main(string[] args)
        {

            //*************** Pakete erstellen******************
            UInt16 Paklänge = 10; 
            byte[] Paklänge_arr = BitConverter.GetBytes(Paklänge);
                             
            byte videoIDa = 0x11; //videoID Byte 1 als hex
            byte[] videoIDa_arr = BitConverter.GetBytes(videoIDa);

            byte videoIDb = 0x11; //videoID Byte 2 als hex
            byte[] videoIDb_arr = BitConverter.GetBytes(videoIDb);

            UInt32 counter = 1000; //Hole Zählerwert mit 4 Byte
            byte[] counter_arr = BitConverter.GetBytes(counter);

            Int32 reserve = 11; //4 Byte reserve
            byte[] reserve_arr = BitConverter.GetBytes(reserve);

            MemoryStream memStream = new MemoryStream();
            memStream.Write(Paklänge_arr, 0, Paklänge_arr.Length);
            memStream.Write(videoIDa_arr, 0, 1);
            memStream.Write(videoIDb_arr, 0, 1);
            memStream.Write(counter_arr, 0, videoIDa_arr.Length);
            memStream.Write(reserve_arr, 0, reserve_arr.Length);

            byte[] DataPaket = memStream.ToArray();

            Console.WriteLine("Paket erstellt mit {0} Bytes",DataPaket.Length);
            
            //***Paket2****
            UInt16 Paklänge2 = 8;
            byte[] Paklänge_arr2 = BitConverter.GetBytes(Paklänge2);

            byte videoIDa2 = 0x22; //videoID Byte 1 als hex
            byte[] videoIDa_arr2 = BitConverter.GetBytes(videoIDa2);

            byte videoIDb2 = 0x22; //videoID Byte 2 als hex
            byte[] videoIDb_arr2 = BitConverter.GetBytes(videoIDb2);

            UInt32 counter2 = 1000; //Hole Zählerwert mit 4 Byte
            byte[] counter_arr2 = BitConverter.GetBytes(counter2);

            Int16 reserve2 = 22; //4 Byte reserve
            byte[] reserve_arr2 = BitConverter.GetBytes(reserve2);

            MemoryStream memStream2 = new MemoryStream();
            memStream2.Write(Paklänge_arr2, 0, Paklänge_arr2.Length);
            memStream2.Write(videoIDa_arr2, 0, 1);
            memStream2.Write(videoIDb_arr2, 0, 1);
            memStream2.Write(counter_arr2, 0, videoIDa_arr2.Length);
            memStream2.Write(reserve_arr2, 0, reserve_arr2.Length);

            byte[] DataPaket2 = memStream2.ToArray();

            Console.WriteLine("Paket erstellt mit {0} Bytes", DataPaket2.Length);

            //***Paket3****
            UInt16 Paklänge3 = 14;
            byte[] Paklänge_arr3 = BitConverter.GetBytes(Paklänge3);

            byte videoIDa3 = 0x33; //videoID Byte 1 als hex
            byte[] videoIDa_arr3 = BitConverter.GetBytes(videoIDa3);

            byte videoIDb3 = 0x33; //videoID Byte 2 als hex
            byte[] videoIDb_arr3 = BitConverter.GetBytes(videoIDb3);

            UInt64 counter3 = 1000; //Hole Zählerwert mit 4 Byte
            byte[] counter_arr3 = BitConverter.GetBytes(counter3);

            Int64 reserve3 = 33; //4 Byte reserve
            byte[] reserve_arr3 = BitConverter.GetBytes(reserve3);

            MemoryStream memStream3 = new MemoryStream();
            memStream3.Write(Paklänge_arr3, 0, Paklänge_arr3.Length);
            memStream3.Write(videoIDa_arr3, 0, 1);
            memStream3.Write(videoIDb_arr3, 0, 1);
            memStream3.Write(counter_arr3, 0, videoIDa_arr3.Length);
            memStream3.Write(reserve_arr3, 0, reserve_arr3.Length);

            byte[] DataPaket3 = memStream3.ToArray();

            Console.WriteLine("Paket erstellt mit {0} Bytes", DataPaket3.Length);
            Console.WriteLine("");
                        
        //****************************Pakete zusammenführen***************************
            List<byte> list1 = new List<byte>(DataPaket);
            List<byte> list2 = new List<byte>(DataPaket2);
            list1.AddRange(list2);
            byte[] ZweiPakete = list1.ToArray();

            Console.WriteLine("ZweiPakete Array erstellt mit {0} Bytes", ZweiPakete.Length);

             List<byte> list3 = new List<byte>(ZweiPakete);
            List<byte> list4 = new List<byte>(DataPaket3);
            list3.AddRange(list4);
            byte[] DreiPakete = list3.ToArray();

            Console.WriteLine("DreiPakete Array erstellt mit {0} Bytes", DreiPakete.Length);
            Console.WriteLine("");

            //Die Länge der Empfangenen Nachricht bzw die Länge der drei Pakete
            int Nachrichtenlaenge = DreiPakete.Length;

        //*****************Pakete in EmpfangsBuffer[] kopieren*****************************

            byte[] Empfangsbuffer = new Byte[50]; //Buffer 50byte groß

            Buffer.BlockCopy(DreiPakete, 0, Empfangsbuffer, 0, Nachrichtenlaenge);
                    
         //****Empfangsbuffer[] in Temp[] kopieren (Array hat länge der Nachrichten)********

            byte[] Temp = new Byte[Nachrichtenlaenge];
            Buffer.BlockCopy(Empfangsbuffer, 0, Temp, 0, Nachrichtenlaenge);

          //*************Daten Pakete auslesen und trennen mit SCHLEIFE************************

            int pos = 0;
            while (pos < Temp.Length)
            {
                pos = GetPacket(Temp, pos);

            }
        }
        
        public static int GetPacket(byte[] data, int startIndex)
        {
            //Paketlänge aus Paket holen bzw. erste zwei bytes zu int
            UInt16 PaketlaengenInfo =  BitConverter.ToUInt16(data, startIndex);

            //zur Kontrolle ob er auch wirklich die zwei byte ausliest
            Console.WriteLine("Paketlängeninformation {0}", PaketlaengenInfo);
            Console.WriteLine("");
            
            //kopiere die Daten aus data[] zu Paket[] mit der länge des Pakets 
            byte[] Paket = new Byte[PaketlaengenInfo];
            Buffer.BlockCopy(data, 0, Paket, 0, PaketlaengenInfo);

            //DummyMethode ausführen
            ConvertVideo(Paket);

            return startIndex + PaketlaengenInfo;
        }
                        
        //*************Dummy Methode************************
        public static void ConvertVideo(byte[] DataPakets)
        {
            //Paketinhalt wiedergeben zur Kontrolle
            Console.WriteLine(BitConverter.ToString(DataPakets));
            Console.WriteLine("");
        }
 
    }
}

der Code kann direkt kopiert und ausgeführt werdne.

mfg
Berti

B
Bartando77 Themenstarter:in
14 Beiträge seit 2010
vor 13 Jahren

Ich denke der Fehler liegt hier:


   //kopiere die Daten aus data[] zu Paket[] mit der länge des Pakets 
            byte[] Paket = new Byte[PaketlaengenInfo];
            Buffer.BlockCopy(data, 0, Paket, 0, PaketlaengenInfo);

Der Source darf ja nicht den Offset 0 haben, welchen offset müsste ich denn da eintragen damit er immer das nächste Telegramm nimmt und nicht immer bei 0?

Müsste das Startindex sein ?

Edit: ja es muss startindex sein! könnte vielleicht jemand nachschauen ob auch alles schön richtig ist?^^ hab gerade bissl glückshormone weils so klappt 😄

B
Bartando77 Themenstarter:in
14 Beiträge seit 2010
vor 13 Jahren

so gehts 😃

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Threading;


namespace schleifentest
{
    class Program
    {
        static void Main(string[] args)
        {

            //*************** Pakete erstellen******************
            UInt16 Paklänge = 10; 
            byte[] Paklänge_arr = BitConverter.GetBytes(Paklänge);
                             
            byte videoIDa = 0x11; //videoID Byte 1 als hex
            byte[] videoIDa_arr = BitConverter.GetBytes(videoIDa);

            byte videoIDb = 0x11; //videoID Byte 2 als hex
            byte[] videoIDb_arr = BitConverter.GetBytes(videoIDb);

            UInt32 counter = 1000; //Hole Zählerwert mit 4 Byte
            byte[] counter_arr = BitConverter.GetBytes(counter);

            Int32 reserve = 11; //4 Byte reserve
            byte[] reserve_arr = BitConverter.GetBytes(reserve);
            Array.Reverse(reserve_arr);

            MemoryStream memStream = new MemoryStream();
            memStream.Write(Paklänge_arr, 0, Paklänge_arr.Length);
            memStream.Write(videoIDa_arr, 0, 1);
            memStream.Write(videoIDb_arr, 0, 1);
            memStream.Write(counter_arr, 0, videoIDa_arr.Length);
            memStream.Write(reserve_arr, 0, reserve_arr.Length);

            byte[] DataPaket = memStream.ToArray();

            Console.WriteLine("Paket erstellt mit {0} Bytes",DataPaket.Length);
            
            //***Paket2****
            UInt16 Paklänge2 = 8;
            byte[] Paklänge_arr2 = BitConverter.GetBytes(Paklänge2);

            byte videoIDa2 = 0x22; //videoID Byte 1 als hex
            byte[] videoIDa_arr2 = BitConverter.GetBytes(videoIDa2);

            byte videoIDb2 = 0x22; //videoID Byte 2 als hex
            byte[] videoIDb_arr2 = BitConverter.GetBytes(videoIDb2);

            UInt32 counter2 = 1000; //Hole Zählerwert mit 4 Byte
            byte[] counter_arr2 = BitConverter.GetBytes(counter2);

            Int16 reserve2 = 22; //4 Byte reserve
            byte[] reserve_arr2 = BitConverter.GetBytes(reserve2);
            Array.Reverse(reserve_arr2);

            MemoryStream memStream2 = new MemoryStream();
            memStream2.Write(Paklänge_arr2, 0, Paklänge_arr2.Length);
            memStream2.Write(videoIDa_arr2, 0, 1);
            memStream2.Write(videoIDb_arr2, 0, 1);
            memStream2.Write(counter_arr2, 0, videoIDa_arr2.Length);
            memStream2.Write(reserve_arr2, 0, reserve_arr2.Length);

            byte[] DataPaket2 = memStream2.ToArray();

            Console.WriteLine("Paket erstellt mit {0} Bytes", DataPaket2.Length);

            //***Paket3****
            UInt16 Paklänge3 = 14;
            byte[] Paklänge_arr3 = BitConverter.GetBytes(Paklänge3);

            byte videoIDa3 = 0x33; //videoID Byte 1 als hex
            byte[] videoIDa_arr3 = BitConverter.GetBytes(videoIDa3);

            byte videoIDb3 = 0x33; //videoID Byte 2 als hex
            byte[] videoIDb_arr3 = BitConverter.GetBytes(videoIDb3);

            UInt64 counter3 = 1000; //Hole Zählerwert mit 4 Byte
            byte[] counter_arr3 = BitConverter.GetBytes(counter3);

            Int64 reserve3 = 33; //4 Byte reserve
            byte[] reserve_arr3 = BitConverter.GetBytes(reserve3);
            Array.Reverse(reserve_arr3);

            MemoryStream memStream3 = new MemoryStream();
            memStream3.Write(Paklänge_arr3, 0, Paklänge_arr3.Length);
            memStream3.Write(videoIDa_arr3, 0, 1);
            memStream3.Write(videoIDb_arr3, 0, 1);
            memStream3.Write(counter_arr3, 0, videoIDa_arr3.Length);
            memStream3.Write(reserve_arr3, 0, reserve_arr3.Length);

            byte[] DataPaket3 = memStream3.ToArray();

            Console.WriteLine("Paket erstellt mit {0} Bytes", DataPaket3.Length);
            Console.WriteLine("");
                        
        //****************************Pakete führen*********************************************
            List<byte> list1 = new List<byte>(DataPaket);
            List<byte> list2 = new List<byte>(DataPaket2);
            list1.AddRange(list2);
            byte[] ZweiPakete = list1.ToArray();

            Console.WriteLine("ZweiPakete Array erstellt mit {0} Bytes", ZweiPakete.Length);

             List<byte> list3 = new List<byte>(ZweiPakete);
            List<byte> list4 = new List<byte>(DataPaket3);
            list3.AddRange(list4);
            byte[] DreiPakete = list3.ToArray();

            Console.WriteLine("DreiPakete Array erstellt mit {0} Bytes", DreiPakete.Length);
            Console.WriteLine("");

            //Die Länge der Empfangenen Nachricht bzw die Länge der drei Pakete
            int Nachrichtenlaenge = DreiPakete.Length;

        //*****************Pakete in EmpfangsBuffer[] kopieren*****************************

            byte[] Empfangsbuffer = new Byte[50]; //Buffer 50byte groß

            Buffer.BlockCopy(DreiPakete, 0, Empfangsbuffer, 0, Nachrichtenlaenge);
                    
         //****Empfangsbuffer[] in Temp[] kopieren (Array hat länge der Nachrichten)********

            byte[] Temp = new Byte[Nachrichtenlaenge];
            Buffer.BlockCopy(Empfangsbuffer, 0, Temp, 0, Nachrichtenlaenge);

          //*************Daten Pakete auslesen und trennen*******************************

            int pos = 0;
            while (pos < Temp.Length)
            {
                pos = GetPacket(Temp, pos);

            }
        }
        
        public static int GetPacket(byte[] data, int startIndex)
        {
            //Paketlänge aus Paket holen bzw. erste zwei bytes zu int
            UInt16 PaketlaengenInfo =  BitConverter.ToUInt16(data, startIndex);

            //zur Kontrolle ob er auch wirklich die zwei byte ausliest
            Console.WriteLine("Paketlängeninformation {0}", PaketlaengenInfo);
            Console.WriteLine("");
            
            //kopiere die Daten aus data[] zu Paket[] mit der länge des Pakets 
            byte[] Paket = new Byte[PaketlaengenInfo];
            Buffer.BlockCopy(data, startIndex, Paket, 0, PaketlaengenInfo);

            //DummyMethode ausführen
            ConvertVideo(Paket);

            return startIndex + PaketlaengenInfo;
        }
                        
        //*************Dummy Methode************************
        public static void ConvertVideo(byte[] DataPakets)
        {
            //Paketinhalt wiedergeben zur Kontrolle
            Console.WriteLine(BitConverter.ToString(DataPakets));
            Console.WriteLine("");
        }
 
    }
}

1.361 Beiträge seit 2007
vor 13 Jahren

Hi,

Beim Lesen musst du nicht ständig ein neues Byte-Array blockCopy-en.
Anstatt auf byte[]-Arrays mit BitConverter zu arbeiten, pack um das byte[]-Array lieber einen MemoryStream und um diesen einen BinaryReader. Dann geht das wesentlich komfortabler, du musst dir keinen aktuellen Index/Position merken und liest päckchenweise einfach hintereinander weg !

Beim schreiben solltest du natürlich auch den BinaryWriter verwenden.

So wird aus

UInt16 Paklänge = 10;
byte[] Paklänge_arr = BitConverter.GetBytes(Paklänge);

byte videoIDa = 0x11; //videoID Byte 1 als hex
byte[] videoIDa_arr = BitConverter.GetBytes(videoIDa);

byte videoIDb = 0x11; //videoID Byte 2 als hex
byte[] videoIDb_arr = BitConverter.GetBytes(videoIDb);

UInt32 counter = 1000; //Hole Zählerwert mit 4 Byte
byte[] counter_arr = BitConverter.GetBytes(counter);

Int32 reserve = 11; //4 Byte reserve
byte[] reserve_arr = BitConverter.GetBytes(reserve);
Array.Reverse(reserve_arr);

MemoryStream memStream = new MemoryStream();
memStream.Write(Paklänge_arr, 0, Paklänge_arr.Length);
memStream.Write(videoIDa_arr, 0, 1);
memStream.Write(videoIDb_arr, 0, 1);
memStream.Write(counter_arr, 0, videoIDa_arr.Length);
memStream.Write(reserve_arr, 0, reserve_arr.Length);

byte[] DataPaket = memStream.ToArray();

dann

MemoryStream memStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(memStream);

writer.Write((UInt16)10);   // Paklänger
writer.Write((Byte)0x11);   //videoID Byte 1 als hex
writer.Write((Byte)0x11);   //videoID Byte 2 als hex
writer.Write((UInt32)1000); //Hole Zählerwert mit 4 Byte
writer.Write((Int32)11);    //4 Byte reserve

byte[] DataPaket = memStream.ToArray();

beste Grüße
zommi

//Edit:
Und anstatt Array.Reverse(...) kannst du deinen Zahlwert auch mittels IPAddress.HostToNetworkOrder(...) nach BigEndian konvertieren.

Thema geschlossen