Avatar billede skurggman Nybegynder
03. februar 2005 - 19:10 Der er 26 kommentarer og
1 løsning

Filsender over UDP

Hej

Jeg har fået som ugeopgave at lave en filsender med protokollen UDP. Det er såmen ikke forbindelsen der er noget galt med, men i min while løkke som sender pakker i passende størrelse til klienten, sender den hele bufferen afsted i den sidste løkke - hvor den kun burde at sende længden af det den har læst afsted fra bufferen... Hvor går det galt med min length variabel?

Koden til Sender er her:
public class Sender {
    private static DatagramSocket s;
   
    public void send(String host, int port, byte[] _buffer, int _length) throws IOException {
        InetAddress recv = InetAddress.getByName(host);
        DatagramPacket packet = new DatagramPacket(_buffer, _length, recv, port);
        s.send(packet);
    }
   
    public static void main(String args[]){
        String filename = args[0];
        String receiver = args[1];
        int port = Integer.parseInt(args[2]);
        byte[] buffer = new byte[640];
        int length = 0;
        try {
            s = new DatagramSocket();
            FileInputStream reader = new FileInputStream(filename);
            Sender sender = new Sender();
            int i = 0;
            while((length = reader.read(buffer)) != -1){
                System.out.println(length);
                sender.send(receiver, port, buffer, length);
                String test = new String(buffer);
                System.out.println(test);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

På forhånd tak og jeg håber i forstår spørgsmålet, som altså er: Hvorfor kommer sender den for meget i den sidste løkke gennemgang?

Hvis i er interesseret i at teste den på egenmaskine kan i hente dem her:

www.daimi.au.dk/~rauff/Sender.java
www.daimi.au.dk/~rauff/Receiver.java

/Kim
Avatar billede _carsten Nybegynder
03. februar 2005 - 19:14 #1
Prøv at afslutte din send metode i Sender med flush()
Avatar billede _carsten Nybegynder
03. februar 2005 - 19:17 #2
Fik vist læst for lidt på teksten


Sådan
        s.send(packet);
        s.flush();
    }
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:19 #3
Det er vel for såvidt ligegyldigt, det er ikke det at skrive til filen der er et problem - det er at den skriver for meget og ikke for lidt :)

Men jeg prøver det...
Avatar billede _carsten Nybegynder
03. februar 2005 - 19:23 #4
Nogen gange skal man bruge hovedet inden man kommer med en masse forslag - et kig i API'et siger at flush() ikke kan anvendes her, så GLEM alt det sludder jeg pt. har skrevet.
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:23 #5
Det skulle jeg også lige til at skrive... :)
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:25 #6
Problemet er at der bliver hvis der kun bliver læst 500 byte ind i bufferen(i sidste gennemløb) og skal sendes, så sender den alligeve 640 - selvom jeg har length indlæst og sendt med...

Så de sidste 140 bliver altså også sendt med og skrevet i filen, hvilket de ikke skal.
Avatar billede arne_v Ekspert
03. februar 2005 - 19:25 #7
Hvad er packet.getLength() ovre i receiver ?
Avatar billede arne_v Ekspert
03. februar 2005 - 19:26 #8
Min hypotese er at packet.getData().length er større end packet.getLength() og at
du skal new'e packet.getLength() bytes ig System.arraycopy'e fra packet.getData()
til den nye buffer.
Avatar billede arne_v Ekspert
03. februar 2005 - 19:26 #9
Har I iøvrigt overvejet hvorvidt UDP er et godt valg til fil overførsel ?
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:28 #10
Det er en metode der returnere længden af packet, som er den pakke man sender afsted med UDP protokollen. Det er ikke en funktion jeg har indbygget :) Men altså en der hører sammen med datagramPacket klassen.

Kig eventuelt i: www.daimi.au.dk/~rauff/Receiver.java
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:29 #11
Ja det har vi overvejet og det er den IKKE! Men det er som sagt en uge opgave hvor vi specifikt skal bruge den protokol til at lege med.

Vi bruger også TCP protokollen...

Jeg forstår ikke helt hvad du mener arne_v - kan du give et eksempel?
Avatar billede arne_v Ekspert
03. februar 2005 - 19:31 #12
Ja - jeg ved godt at getLength er en indbygget metode og jeg har kigget
i Receiver.java.

Mit forslag er at du tester om den returnerer den rigtige længde og hvis den gør, så
implementerer du som jeg beskrev 19:26:26
Avatar billede arne_v Ekspert
03. februar 2005 - 19:32 #13
OK. Fordi medmindre i nummererer pakkerne og checker for manglende pakker og
forkert rækkefølge så kan det gå grueligt galt.
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:33 #14
Min hypotese er at packet.getData().length er større end packet.getLength() og at
du skal new'e packet.getLength() bytes ig System.arraycopy'e fra packet.getData()
til den nye buffer.

>>> Det er netop det her jeg ikke forstår - jeg har testet at getLength faktisk returnerer den rigtige længde...
Avatar billede arne_v Ekspert
03. februar 2005 - 19:36 #15
Jeg vil erstatte

byte[] out = packet.getData();

med:

byte[] out = new byte[packet.getLength()];
System.arraycopy(packet.getData(), 0, out, 0, packet.getLength());
Avatar billede arne_v Ekspert
03. februar 2005 - 19:36 #16
i Receiver.java
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:42 #17
Det hjalp ikke. Jeg er også meget sikker på at det er i Sender det er galt, da jeg laver en system.out.println på alt den sender og kan se at den sender for meget.

Nu fucker den også starten af filen op...
Avatar billede skurggman Nybegynder
03. februar 2005 - 19:45 #18
Hvis jeg sender filen Sender.java - altså koden I har ovenstående, så får jeg det her i filename.txt - som er filen jeg sender til i klienten(receiver):

import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
* @author rauff
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class Sender {
    private static DatagramSocket s;
   
    public void send(String host, int port, byte[] _buffer, int _length) throws IOException {
        InetAddress recv = InetAddress.getByName(host);
        DatagramPacket packet = new DatagramPacket(_buffer, _length, recv, port);
        s.send(packet);
    }
   
    public static void main(String args[]){
        String filename = args[0];
        String receiver = args[1];
        int port = Integer.parseInt(args[2]);
        byte[] buffer = new byte[640];
        int length = 0;
        try {
            s = new DatagramSocket();
            FileInputStream reader = new FileInputStream(filename);
            Sender sender = new Sender();
            int i = 0;
            while((length = reader.read(buffer)) != -1){
                System.out.println(length);
                sender.send(receiver, port, buffer, length);
                String test = new String(buffer);
                System.out.println(test);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
;
    }
   
    public static void m


----------------------------

Altså:
";
    }
   
    public static void m

"
Det her for meget.
Avatar billede arne_v Ekspert
03. februar 2005 - 19:52 #19
Hvordan kan du få for meget hvis packet.getLength() returnerer den rigtige længde ?
Avatar billede skurggman Nybegynder
03. februar 2005 - 20:05 #20
Jeg fatter det simpelthen ikke...
Jeg bruger da heller ikke packet.getLength() nogen steder gør jeg?

Det er altså her der er noget galt så vidt jeg kan komme frem til:
           
while((length = reader.read(buffer)) != -1){
    System.out.println(length);
    sender.send(receiver, port, buffer, length);
        String test = new String(buffer);
        System.out.println(test);
    }

Hvis man sender sender.java - så passer det med 2 pakker der skal sendes, den ene pakke har en størrelse på 640 og den andet 609 står der når jeg skriver min length ud under vejs... det er alt sammen meget mystisk og lige pludselig finder man fejlen og grimmer sig :)
Avatar billede skurggman Nybegynder
03. februar 2005 - 20:05 #21
Sorry 606 (ikke 609) - om det gør en forskel.
Avatar billede arne_v Ekspert
03. februar 2005 - 20:28 #22
Nu har jeg hentet dine 2 filer.

Jeg retter Receiver.java til:

    public static byte[] receive(int port) throws IOException {
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        String temp = new String(buffer);
        //System.out.println(temp);
        s.receive(packet);
        byte[] out = new byte[packet.getLength()];
        System.arraycopy(packet.getData(), 0, out, 0, packet.getLength());
        //System.out.println(out);
        return out;
    }

og så modtager den de korrekte data !
Avatar billede arne_v Ekspert
03. februar 2005 - 20:28 #23
Og for at Sender udskriver det rigtige på skærmen så skal den rettes til:

            while((length = reader.read(buffer)) != -1){
                System.out.println(length);
                sender.send(receiver, port, buffer, length);
                String test = new String(buffer, 0, length);
                System.out.println(test);
            }
Avatar billede arne_v Ekspert
03. februar 2005 - 20:29 #24
Rettelsen i Receiver er den jeg har forklaret.

Rettelsen i Sender er en triviel med at tilføje længden i:

String test = new String(buffer, 0, length);
Avatar billede skurggman Nybegynder
03. februar 2005 - 21:27 #25
Ja nu ser det sgu ud til at det virker!

Mange tak for hjælpen!
Smider du lige et svar?
Avatar billede arne_v Ekspert
03. februar 2005 - 21:30 #26
svar
Avatar billede skurggman Nybegynder
03. februar 2005 - 21:41 #27
Mange tak!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester