Dela upp en Byte[] i flera små för att skicka via UDP?

Permalänk

Dela upp en Byte[] i flera små för att skicka via UDP?

Har frågat runt på nätet utan något resultat, fast ja tror att det är en relativt enkel fråga.

här är en kod

byte[] u = imageToByteArray(holder); buff = new byte[16192]; int c = 0; for (int i = 0; i < u.Length; i++) { buff[c] = u[i]; c++; // MessageBox.Show(u.Length.ToString()); udpcap.Send(buff, buff.Length, adress.Address.ToString(), 1700); }

Problemet med den är, den delar inte upp det den ska skicka rätt, utan den skickar bara och tillslut åker den utanför index.

Jag är ny på programmering så ja är fast här.

Ska man skicka med ett paket ka ja göra det utan större problem, men det är att dela upp dom ja inte har någon funktion för.

Hoppas nån här förstår va ja försöker göra.

Tack!

Permalänk
Medlem

Nu vet jag inte exakt vad din uppgift är, men att använda UDP för att skicka något som behöver delas upp är inte riktigt att rekommendera då du med UDP inte har någon 'säkerhet' att saker kommer fram samt att de kommer fram i rätt ordning, till skillnad från TCP. Dvs UDP bör användas då datan i sig inte är "viktig" och att den kan tolkas för sig oberoende av paketens ordning.

Utöver det är din kod nog lite felaktig, bland annat skapar du en array med 16192 element varpå du i loopen endast "kopierar" ett element(byte) i taget och skickar sedan iväg hela (? alt 1700 ? ) bufferten som antagligen då består av massa tomma bytes.
För att sedan gör om detta gång på gång med enda skillnaden att du har en byte till för varje iteration. Så det ser ut när jag tittar på det iaf.

Visa signatur

Spelrigg: 800D| i7 3930K@4,7 GHz - Custom WC | 32 GB Kingston HyperX Beast | 7970 GHz X-Edition |1x30 Dell U3011, 2x27" | Sennheiser HD650 | Xonar Essence STX |
Laptop: G74SX 17,3" 120 Hz 3D |
Server: Phenom II X4 955BE | Corsair XMS3 8 GB | 16 HDDs, 27 TB |
HTPCs: ASUS EEE Box 1.8 Ghz | Blu-Ray | OCZ Vertex 2 60 GB | 4 GB RAM |

Permalänk

Jo vet att UDP inte "is the shit" om man säger så. Men vill gärna få igång det. Det är inte som att min användning är för bankuppgifter om man säger så;P

Och jo vet att den är felaktigt, men vet inte hur ja ska fixa.

Det ja vill göra är, skicka hela byte arrayen i bitar, så om vi säger 10 bitar, så skickar den, 1 2 3 ... 10, sen är det klart.

Om ja kunde få exempel på det, för förstår inte hur ja ska göra det.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Det ja vill göra är, skicka hela byte arrayen i bitar, så om vi säger 10 bitar, så skickar den, 1 2 3 ... 10, sen är det klart.

Om ja kunde få exempel på det, för förstår inte hur ja ska göra det.

Först och främst vill du som sagt kopiera mer än ett element ur u och sedan måste man också hålla reda på att man inte hamnar utanför fälten.

byte[] u = imageToByteArray(holder); buff = new byte[16192]; int c = 0; int size = u.Length/10; for (int i = 0; i < u.Length; i += size) { // buff[c] = u[i]; // c++; c = Math.Min(size, u.Length-i); Array.Copy(u, i, buff, 0, c); // MessageBox.Show(u.Length.ToString()); udpcap.Send(buff, c, adress.Address.ToString(), 1700); }

Egentligen vill man nog dock hellre ha en fast paketstorlek och variera antalet paket än tvärt om.

Permalänk

Nu börjar det lita nåt:)

skulle vilja ha som du säger dock, fast paket storlek.

Dock när ja testa det här, funka det inte i slutet på recieve delen konstigt nog.

byte[] data = udpcap.Receive(ref adress); if (data.Length != 0) { databyte = data; } if (data.Length == 0) { pictureBox1.BackgroundImage = byteArrayToImage(databyte); }

Dock verkar ja gjort helt fel här när ja väl kollar storleken på databyte i slutet;S
så hjälp är ja tacksam för.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

if (data.Length == 0)

Något paket med längd 0 kommer man nog aldrig att se dock; sändningsloopen skickar size byte i taget och därefter resten (om det blir mindre än size byte över).
Och på ungefär samma sätt som vid sändning (fast tvärtom) måste man pussla ihop de tio bitarna till en stor byte[] innan man kan skicka denna till byteArrayToImage().

Att få det att fungera kan förvisso vara en trevlig övning, men att välja tcp skulle som sagt sannolikt vara både enklare och tillförlitligare.

Permalänk

har gjort så att den sänder ett tomt paket precis efter for loopen, men går säkerligen gör bättre.

Men försöker mig på for loopen för att sätta ihop bitarna, går som det går dock, vet inte hur ja ska sätta ihop även fast ja kollar på koden;S

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Men försöker mig på for loopen för att sätta ihop bitarna, går som det går dock, vet inte hur ja ska sätta ihop även fast ja kollar på koden;S

Det fjärde argumentet till Array.Copy() anger på vilken position man vill skriva, så börja med att skapa en stort tomt fält och gör något liknande för att kopiera in mottagen data (och hoppas att alla bitar kommer i rätt ordning).

Array.Copy(data, 0, nyttOchStort, i, data.Length); i += data.Length

Permalänk

Okej går inte höjdare, skrev så här:

byte[] data = udpcap.Receive(ref adress); if (data.Length != 0) { int size = data.Length / 10; for (int i = 0; i < data.Length; i += size) { Array.Copy(data, 0, databyte, i, data.Length); i += data.Length; } }

vilket förmodligen är helt fel;S

Permalänk
Hedersmedlem

size är inget du behöver tänka på här, men man måste se till att man kopierar in 10 datablock i databyte. Tänk:
1. Mottag det första paketet
2. Kopiera in paketets data på position 0 i databyte
3. Mottag det andra paketet
4. Kopiera in paketets data i databyte efter det första paketets data (dvs. på position paket1.Length)
....
19. Mottag det 10:e paketet
20. Kopiera in paketets data i databyte efter det nionde paketets data (dvs. på position paket1.Length+paket2.Length + ... + paket9.Length)
21. Klar

Permalänk

Jo alltså fattar själva tanken, men förstår ändå inte hur ja ska sätta bit efter bit.

Array.Copy(data, 0, databyte, i, data.Length);
i += data.Length;

Jag antar att det där sätter paket 1 på plats 0, sen 2 på 1 etc?

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Jo alltså fattar själva tanken, men förstår ändå inte hur ja ska sätta bit efter bit.

Array.Copy(data, 0, databyte, i, data.Length);
i += data.Length;

Jag antar att det där sätter paket 1 på plats 0, sen 2 på 1 etc?

Ja, om man tänker sig databyte som
[0000000000 0000000000 0000000000 0000000000]
och data1 = [11111], data2 = [22222] och data3 = [33333]
kommer

Array.Copy(data1, 0, databyte, 0, data1.Length); Array.Copy(data2, 0, databyte, data1.Length, data2.Length); Array.Copy(data3, 0, databyte, 27, data3.Length-1);

till exempel ge databyte värdet
[1111122222 0000000000 0000000333 3000000000]

Permalänk

Men hur ska for loopen se ut;S?

Försöker mig på den, men går lite som det går tyvärr.

i += data.length får (value cannot be null), och sen är ja fast.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Men hur ska for loopen se ut;S?

Försöker mig på den, men går lite som det går tyvärr.

i += data.length får (value cannot be null), och sen är ja fast.

Ungefär såhär kanske?

byte[] nyttOchStort = new byte[161920]; int i = 0; for(int q = 0; q < 10; ++q) { byte[] data = udpcap.Receive(ref adress); Array.Copy(data, 0, nyttOchStort, i, data.Length); i += data.Length }

Permalänk

Det funkar delvis, dock skiftar bilden i storlek hela tiden, och då failar den.
Ja testa öka delningen till 100, då höll den lite längre, sen faila det.

Bilden är en print screen av skärmen, så den ändras ju när skärmen ändras, vilket den görs hela tiden om man gör nåt.

Permalänk

ska jag dra upp koden för att visa?
för allting funkar perfekt så länge inte bilden ändras för mycket typ.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

ska jag dra upp koden för att visa?
för allting funkar perfekt så länge inte bilden ändras för mycket typ.

Fungerar det om du bara skickar en gång eller skickar samma bild hela tiden? Ett eventuellt tappat paket skulle ju också få alla efterföljande att komma på fel ställe...

Permalänk

Det funkar om ja skickar liknande bild. Tex, ja visar up bilden helatiden (så om ja tar print screen och visar den, blri det ju sån där, Warp effekt).

Så om ja tar en liten ruta, iv säger 800x600, och gör så att inget rör sig där, då kan den skicka den bilden hela tiden.
Sen om ja rör någonting där, KAN det faila, eller inte, men det verkar faila rätt fort om det ändras häftigt i storleken antar jag.

Graphics graphics = Graphics.FromImage(holder); graphics.CopyFromScreen(0, 0, 0, 0, new Size(1920, 1200), CopyPixelOperation.SourceCopy); byte[] u = imageToByteArray(holder); int c = 0; int size = u.Length / 10; buff = new byte[16120]; for (int i = 0; i < u.Length; i += size) { c = Math.Min(size, u.Length - i); Array.Copy(u, i, buff, 0, c); udpcap.Send(buff, c, adress.Address.ToString(), 1700); }

Där är alltså hela sänd koden, den tar kort sätter in den i en bitmap (bitmapen görs i sänd koden innan while loopen, och den är lika stor som print screenen, alltså 1920x1200).

Sen gör ja bilden till en byte array, skickar den i 10 bitar, sen pusslar jag ihop den.

databyte = new byte[1619200]; int i = 0; for (int q = 0; q < 11; ++q) { byte[] data = udpcap.Receive(ref adress); Array.Copy(data, 0, databyte, i, data.Length); i += data.Length; } pictureBox1.BackgroundImage = byteArrayToImage(databyte);

Jag får error i

public Image byteArrayToImage(byte[] byteArrayIn) { MemoryStream ms = new MemoryStream(byteArrayIn); Image returnImage = Image.FromStream(ms); return returnImage; }

Additional information: Parameter is not valid.

För den har förmodligen failat med byte arrayen, och försöker göra en bild av, nånting som inte är en bild.
Skulle gärna vilja testa att köra på och ignorera koden, men vet inte om man kan göra det?

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

För den har förmodligen failat med byte arrayen, och försöker göra en bild av, nånting som inte är en bild.
Skulle gärna vilja testa att köra på och ignorera koden, men vet inte om man kan göra det?

Enklast är att införa ett try-catch-block

public Image byteArrayToImage(byte[] byteArrayIn) { try { MemoryStream ms = new MemoryStream(byteArrayIn); Image returnImage = Image.FromStream(ms); return returnImage; } catch(Exception e) { return new Bitmap(1,1); } }

men risken är att man, då ett tappat paket innebär att man kommer i otakt med sändaren, förmodligen inte kommer se någon korrekt bild på länge. Testa att jämföra hur många paket som har skickats med hur många som har mottagits.

Permalänk

Testade det, då skickaden på bilder, sen blev det ingen bild alls, bara grått.

Eller vänta, verkar som den kan dra igång igen, sen bli grå igen.

Hmm, vet inte vad som försigår.

Finns det något vettigare sätt att göra det ja försöker göra kanske?
helst med UDP dock, klarar mig på korrumperade bilder här och var, men att inte få någon bild alls dock är ingen höjdare.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Testade det, då skickaden på bilder, sen blev det ingen bild alls, bara grått.

Eller vänta, verkar som den kan dra igång igen, sen bli grå igen.

Hmm, vet inte vad som försigår.

Om ett fel uppstår sätts bilden till "new Bitmap(1,1);", vilket ger den grå färgen. Om man fortsätter (och tappar lagom många fler paket) kanske det blir rätt senare...

Permalänk

Jo såg det, antar att det blir fel fort som bara den;S
förstår inte att det blir totalt fel dock, men la till det här i förra posten:

Finns det något vettigare sätt att göra det ja försöker göra kanske?
helst med UDP dock, klarar mig på korrumperade bilder här och var, men att inte få någon bild alls dock är ingen höjdare.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Finns det något vettigare sätt att göra det ja försöker göra kanske?
helst med UDP dock, klarar mig på korrumperade bilder här och var, men att inte få någon bild alls dock är ingen höjdare.

Man skulle till exempel kunna lägga till en räknare (från 0 till 9) i byte 0 i varje paket och i mottagaren börja på en ny bild varje gång man får "0" och rita upp bilden varje gång man får "9" (förutsatt att man fått 10 paket). Då man även kan använda räknarvärdet till att lista ut vart man skall kopiera paketets innehåll blir man också lite mera okänslig för att paket kommer i oordning.

Permalänk

Det låter vettigt, finns det något lätt sätt att åstadkomma det?
då som du säkert märkt, är ja inte så jäkla på det här och är i klar läro fas.

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Det låter vettigt, finns det något lätt sätt att åstadkomma det?
då som du säkert märkt, är ja inte så jäkla på det här och är i klar läro fas.

Nedanstående gör nog ungefär så (och skickar även med hur många paket som totalt behövs). Utrymme för förbättring finns nog, men det lämnas som övning.

int c = 0; byte n = 0; int size = u.Length / 10; byte N = Math.Ceiling(u.Length/(float)size); buff = new byte[16120]; for (int i = 0; i < u.Length; i += size) { c = Math.Min(size, u.Length - i); buff[0] = n++; buff[1] = N; Array.Copy(u, i, buff, 2, c); udpcap.Send(buff, c+2, adress.Address.ToString(), 1700); }

databyte = new byte[1619200]; int i = 0, j = 0; byte n, N; while(true) { byte[] data = udpcap.Receive(ref adress); n = data[0]; N = data[1]; if(n == 0) { i = 0; j = 0; } if(n != N -1 && j < N -1) { Array.Copy(data, 2, databyte, n*(data.Length-2), data.Length-2); i += data.Length; ++j; } else if(j == N-1 && n == N -1) { Array.Copy(data, 2, databyte, i, data.Length-2); pictureBox1.BackgroundImage = byteArrayToImage(databyte); } else break; }

Permalänk

Får tyvärr det här:

Cannot implicitly convert type 'double' to 'byte'. An explicit conversion exists (are you missing a cast?)
byte N = Math.Ceiling(u.Length/(float)size);

Löste det, nu ska ja testa, Tack:)

EDIT:

Verkar fungera utmärkt:!
Nu är det bara att optimera det hela så det går lite fortare, vilket förmodligen går på flera fronter.

Tror du det går att räkna ut hur man kan dela upp varje packet så lite som möjligt?

tex, en bild är 10mb och kan bli 100 paket säger vi, och en annan är 1mb och kan då va 10 paket.
istället för att sätta length / xxx som hugget i sten?
För ja antar att mindre paket = snabbare?

Sen också det här med fragmenterade paket, är dom över 1.5kb blir dom ju fragmenterade, är det bättre att hålla sig under det?
eller ska man bara utgå efter paket gränsen (ca 64kb)?

Tack

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Tror du det går att räkna ut hur man kan dela upp varje packet så lite som möjligt?

tex, en bild är 10mb och kan bli 100 paket säger vi, och en annan är 1mb och kan då va 10 paket.
istället för att sätta length / xxx som hugget i sten?
För ja antar att mindre paket = snabbare?

Sen också det här med fragmenterade paket, är dom över 1.5kb blir dom ju fragmenterade, är det bättre att hålla sig under det?
eller ska man bara utgå efter paket gränsen (ca 64kb)?

Hur stora paketen kan vara utan att fragmenteras beror väl lite på nätverket man skickar dem på, men då även antalet paket skickas med nu kan man sätta size till vad man vill (så länge det inte blir fler än 256 paket totalt). Testa.

Permalänk

Jo men nu är det 1.5k Ethernet som gäller.
Men hur påverkas det av fragmentering?
för läste nånstans att en skrev att det kan gå snabbare att hålla sig under fragmenterings nivån, även om paketen blir mindre.

Men kan tyvärr inget om det.

Citat:

nu kan man sätta size till vad man vill (så länge det inte blir fler än 256 paket totalt). Testa

Måste jag inte ta något tal som är delningsbart med min bild?

Permalänk
Hedersmedlem
Skrivet av Zero Walker:

Måste jag inte ta något tal som är delningsbart med min bild?

Nej, så länge det inte blir fler än 256 paket borde vad som helt fungera. Förmodligen vill man som sagt undvika fragmentering, men vad som är snabbast i ditt nät måste man förmodligen testa sig fram till.

bugg1:

i += data.Length;

borde vara

i += data.Length-2;

Permalänk
Skrivet av Elgot:

Nej, så länge det inte blir fler än 256 paket borde vad som helt fungera. Förmodligen vill man som sagt undvika fragmentering, men vad som är snabbast i ditt nät måste man förmodligen testa sig fram till.

bugg1:

i += data.Length;

borde vara

i += data.Length-2;

Okej, för just nu kör jag en liten fuling.

if (u.Length / 100 < 60000)
{
size = u.Length / 100;
}
else if (u.Length / 50 < 60000)
{
size = u.Length / 50;
}
else if (u.Length / 25 < 60000)
{
size = u.Length / 25;
}

Typ såna grejer, men vill ju hellre ha något som typ.

(Gör så litet som det går)
så den kan byta från 1 paket till 200 och hej vilt, beroende på vad som är lägst för den storleken.

Fixade buggen, va var det för fel?
för fungerar utmärkt före och efter?