Visualizzazione dei risultati da 1 a 8 su 8
  1. #1

    [JAVA] Trasferimento File

    Ho scritto del codice che mi permette di trasferire un file da un server ad un client, solo che nonostante il file arrivi sempre e correttamente a destinazione alcune volte me lo visualizza bene (è un JPG ma può essere qualunque cosa) ed altre non me lo visualizza proprio (File troppo grande o danneggiato).

    Da che può dipendere? Vi scrivo il codice che ho implementato.

    Lato Server
    codice:
    public class ServerP2P
    {
        private ServerSocket server;
        private Socket connessione;
        private String nome;
        
        public ServerP2P (String nome) throws IOException
        {
            this.nome = nome;
            ServerSocket server = new ServerSocket (7778);
            System.out.println ("ServerSocket per il P2P avviato tramite Transfer Thread");
            
            try
            {
                while(true)
                {
                    connessione = server.accept ();
                    P2PHandler c = new P2PHandler (connessione);
                    c.start ();
                }
            }
            catch (Exception e )
            {
                e.printStackTrace ();
            }
        }
    }
    codice:
    public class P2PHandler extends Thread 
    {
        private Socket s;
        private File f;
        private int dimension;
        private byte [] data;
        
        public P2PHandler (Socket s) throws IOException 
        {
            this.s = s;
        }
        
        public void run () 
        {
            try 
            {
                f = new File ("Files\\Prova.jpg");
                dimension = (int)f.length();
                data = new byte [dimension];
                
                while (true)
                {
                    FileInputStream fis = new FileInputStream (f);
                    DataOutputStream opt = new DataOutputStream (s.getOutputStream());
                    fis.read (data, 0, dimension);
                    opt.write (data, 0, dimension);
                    opt.close ();
                    fis.close ();
                }
            } 
            catch (IOException ex) 
            {
                ex.printStackTrace ();
            } 
        }
    }
    Lato Client
    codice:
    public class ClientP2P implements Runnable
    {
        private Socket connessione;
        private Thread listener;
        
        public ClientP2P (String indirizzo)
        {
            try 
            {
                connessione = new Socket (InetAddress.getByName (indirizzo), 7778);
             }
            catch (ConnectException q)
            {
                System.out.println (Eccezione di tipo CONNECT !!!);
            }
            catch (NullPointerException w)
            {
                System.out.println ("Eccezione di tipo NULLPOINTER !!!");
            }
            catch (IOException e) 
            {
                System.out.println ("Eccezione di tipo IO !!!");
            }
            
            listener = new Thread (this);
            listener.start ();
        }
        
        public void run ()
        {
            try
            {
                FileOutputStream fos = new FileOutputStream ("FileRicevuto.jpg");
                DataInputStream dis = new DataInputStream (connessione.getInputStream ());
                byte b [] = new byte [1024];
                while (dis.read (b) != -1)
                {
                    fos.write (b);
                }
          
                dis.close ();
                fos.close ();
                connessione.close ();
            }
            catch (Exception e)
            {
                System.out.println (e);
            }
        }
    }

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: [JAVA] Trasferimento File

    Originariamente inviato da Gil1688
    codice:
                f = new File ("Files\\Prova.jpg");
                dimension = (int)f.length();
                data = new byte [dimension];
                
                while (true)
                {
                    FileInputStream fis = new FileInputStream (f);
                    DataOutputStream opt = new DataOutputStream (s.getOutputStream());
                    fis.read (data, 0, dimension);
                    opt.write (data, 0, dimension);
                    opt.close ();
                    fis.close ();
                }
    Qui lettura/scrittura sono corretti anche se ovviamente sarebbe più furbo leggere/trasferire a "blocchi" invece di caricare per intero il file.

    Il while(true) non ne vedo il senso, non in questo momento (a meno che poi tu abbia in mente di fare un protocollo più complesso con possibilità di gestire più cose).

    P.S. l'uso di DataOutputStream non serve a nulla, non stai usando i metodi specifici di DataOutputStream per scrivere "primitivi" ma lo stai usando solo come "OutputStream".


    Originariamente inviato da Gil1688
    codice:
                FileOutputStream fos = new FileOutputStream ("FileRicevuto.jpg");
                DataInputStream dis = new DataInputStream (connessione.getInputStream ());
                byte b [] = new byte [1024];
                while (dis.read (b) != -1)
                {
                    fos.write (b);
                }
    Il problema è qui. Leggi a blocchi di max 1024 byte. Ma l'ultimo blocco potrebbe non essere di 1024 byte ma di meno!! E il valore di ritorno della read non lo stai usando (a parte il test). Invece ti serve proprio per sapere quanto scrivere del buffer.

    P.S. Idem come sopra il DataInputStream è inutile e non apporta/migliora nulla di più.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Uhm... Quindi qual è la soluzione?
    Leggere a blocchi di 1 nel client?

    E nel lato server, se volessi dividere in blocchi il mio file, come potrei fare?
    Grazie ancora

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Gil1688
    Uhm... Quindi qual è la soluzione?
    Leggere a blocchi di 1 nel client?

    E nel lato server, se volessi dividere in blocchi il mio file, come potrei fare?
    Grazie ancora
    Innanzitutto faccio una precisazione su quanto ho detto prima (ho riletto meglio il tuo codice).
    La ricezione del file è nel client e quindi lì leggi dal socket. Io dicevo che l'ultimo blocco potrebbe non essere della dimensione del buffer. Questo è vero e vale in generale. Ma nel caso di socket le cose vanno ancora peggio!! Perché non essendoci un buffering di mezzo (es. BufferedInputStream) e potendo esserci lentezza/latenza sulla rete, è molto molto probabile che quasi ad ogni read non ottieni esattamente 1024 byte. E per come l'avevi fatto (cioè scrivendo l'intero buffer) ti capita sicuramente di ottenere file estremamente "corrotti".

    Soluzione: innanzitutto sia nel mittente che nel destinatario puoi gestire il trasferimento "a blocchi". L'idioma tipico in genere è:
    - Si istanzia un buffer di byte[] di una certa dimensione (in genere non si spara a caso ma si usano es. 512, 1024, 4096, ecc... non cose esagerate comunque, non si otterrebbero particolari benefici ad avere un buffer di 65536 byte!)
    - Si fa il ciclo in cui si usa il read(byte[] buf) per riempire il buffer per massimo quei N byte. Il punto è che il read restituisce il numero di byte letti e questo va di certo testato (se -1 = EOF). Ma il numero di byte letti deve essere anche usato nel write (precisamente il write(byte[] buf, int off, int len) ) per poter scrivere solo la porzione di buffer riempita dall'ultimo read.

    Altrimenti si scrivono file corrotti e/o di lunghezza sballata.


    P.S. Una cosa: magari non è la tua situazione o tuo interesse ma lo dico lo stesso. Se il mittente dopo aver trasmesso lo stream del file "chiude" la connessione non ci sono problemi nel destinatario, perché effettivamente riceve subito il EOF.
    Se intendi realizzare un protocollo più complesso che permette l'invio di più file sulla stessa connessione, non ti basta più il EOF. Generalmente in questi casi è sempre bene anticipare al destinatario la lunghezza del file. In tali casi i DataOutput/InputStream sono ottimali perché permettono facilmente di scrivere/leggere un primitivo int o long prima dello stream del file per avvertire il destinatario su quanto deve aspettarsi.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Risolverei cambiando così la mia classe P2PHandler del lato server?

    codice:
    public class P2PHandler extends Thread 
    {
        private Socket s;
        private File f;
        private int dimension;
        private byte [] data;
        
        public P2PHandler (Socket s) throws IOException 
        {
            this.s = s;
        }
        
        public void run () 
        {
            try 
            {
                f = new File ("Files\\Prova.jpg");
                dimension = (int)f.length();
                data = new byte [1024];
                
                while (true)
                {
                    FileInputStream fis = new FileInputStream (f);
                    DataOutputStream opt = new DataOutputStream (s.getOutputStream());
                    fis.read (data, 0, dimension);
                    opt.write (data, 0, dimension);
                    opt.close ();
                    fis.close ();
                }
            } 
            catch (IOException ex) 
            {
                ex.printStackTrace ();
            } 
        }
    }
    Così facendo ho cambiato il write lato server, ed il read lato client dovrebbe andare no?

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Gil1688
    Risolverei cambiando così la mia classe P2PHandler del lato server?
    Il vero problema (quello che causa file corrotti) ce l'hai nel client che riceve dal socket e in cui scrivevi sempre tutto il buffer.

    Comunque a scanso di equivoci lo ripeto: sia nel mittente che nel destinatario è perfettamente possibile gestire il trasferimento "a blocchi".
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Per ora ho PROVVISORIAMENTE risolto scrivendo nel server un unico blocco della dimensione del file, e leggendo nel client a blocchi di 1; non corrompendo nulla perciò...

    Certo sarebbe molto meglio se potessi scrivere a blocchi di 1024 e leggere a blocchi di 1024... Per questa seconda opzione, che mi stai consigliando, il client va bene così com'è, ma il server come lo cambio?
    Il buffer anzichè istanziarlo con byte [] data = new byte [dimension] lo istanzio con byte [] data = new byte [1024]; ma poi nel write come mi comporto con offset e length?

    facendo il write come opt.write (data, 0, dimension) ovviamente non mi scrive nulla, mi rimane questo file ricevuto di peso 0... Credo dipenda dall'offset, no? Dovrei aggiornarlo ad ogni ciclo, no?

    Come lo posso fare? Non sò lavorare in byte :S

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Gil1688
    Certo sarebbe molto meglio se potessi scrivere a blocchi di 1024 e leggere a blocchi di 1024...
    E perché non lo fai? ... quale è il dubbio? Ho già spiegato la questione. Una read(byte[] buf) riempie il buffer ma non è detto che lo riempia tutto (specialmente quando si legge da rete o comunque in generale quando è l'ultimo blocco). Il numero di byte letti lo restituisce. E questa lunghezza la devi usare in una write(byte[] buf, int off, int len) per scrivere esattamente quei tot byte letti.
    Se ad un ciclo leggi 1024, scrivi 1024. Se al ciclo successivo leggi 800, scrivi 800 (non scrivi l'intero buffer es. di 1024, altrimenti 800 sono giusti il resto è roba vecchia rimasta nell'array), ecc.....
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.