Avatar billede Slettet bruger
29. september 2012 - 13:33 Der er 16 kommentarer og
1 løsning

Opdele fil i stykker til overførsel vha. TCP

Hej Alle

Jeg skal have lavet mig en simpel applikation i Java, som kan overføre en vilkårlig fil fra en server til en client i bidder af 1000 bytes per styk.

Jeg er lidt på bar bund i forhold til det gøres mest optimalt, og har forsøgt at søge lidt på nettet, men finder ikke nogle rigtig gode eksempler.

Kan en af jer givet et godt eksmpel på dette?

Eller linke til et et?

På forhånd tak!
Avatar billede arne_v Ekspert
29. september 2012 - 14:35 #1
Socket og ServerSocket burde vaere simple at bruge.
Avatar billede arne_v Ekspert
29. september 2012 - 14:39 #2
Her er et 8 aar gammelt eksempel:

import java.io.*;
import java.net.*;

public class Server {
  public static void main(String[] args) throws Exception {
      ServerSocket ss = new ServerSocket(9999);
      Socket s = ss.accept();
      InputStream is = s.getInputStream();
      OutputStream os = new FileOutputStream("C:\\z2.zip");
      byte[] b = new byte[10000];
      int n;
      while((n = is.read(b)) >= 0) {
        os.write(b, 0, n);
      }
      os.close();
      is.close();
  }
}


import java.io.*;
import java.net.*;

public class Client {
  public static void main(String[] args) throws Exception {
      Socket s = new Socket("localhost", 9999);
      OutputStream os = s.getOutputStream();
      InputStream is = new FileInputStream("C:\\z1.zip");
      byte[] b = new byte[10000];
      int n;
      while((n = is.read(b)) >= 0) {
        os.write(b, 0, n);
      }
      os.close();
      is.close();
  }
}
Avatar billede Slettet bruger
29. september 2012 - 20:40 #3
Hej Arne, tak for eksemplet - det var lige præcis hvad jeg søgte!

Jeg har forsøgt at lave en server og en client ud fra dit eksempel, problemet er dog, at hele filen ikke kommer over. (Jpg'er kan f.eks. ikke åbnes.

Kan du gennemskue hvad jeg gør forkert?


    private file_client(String[] args) throws UnknownHostException, IOException
    {
        String answer;
        String ip = args[0];
        String fileName = args[1];
        Socket clientSocket = new Socket(ip, PORT);
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        InputStream inFromServer2 = clientSocket.getInputStream();
        outToServer.writeBytes(fileName + '\n');
        answer = inFromServer.readLine();
        if(Integer.parseInt(answer) != 0){
            int i = 1;
            String[] split = fileName.split("\\.");
            while(TCP.check_File_Exists(fileName) != 0){
                fileName = split[0] + i + "." + split[1];
                i++;
            }

            OutputStream file = new FileOutputStream(fileName);
            byte[] b = new byte[1000];
            int n;
            while((n = inFromServer2.read(b)) >= 0){
                file.write(b,0,n);
            }
        } else {
            System.out.println("File doesn't exist");
        }
        clientSocket.close();
        inFromServer.close();
        inFromServer2.close();
        outToServer.close();
    }


private file_server() throws IOException
    {
        String clientMessage;
        ServerSocket ss = new ServerSocket(PORT);
        while(true){
            Socket s = ss.accept();
            InputStream is = s.getInputStream();
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(is));
            clientMessage = inFromClient.readLine();
            long answer = TCP.check_File_Exists(clientMessage);
            DataOutputStream outToClient = new DataOutputStream(s.getOutputStream());
            outToClient.writeBytes("" + answer + "\n");
            InputStream file = new FileInputStream(clientMessage);
            byte[] b = new byte[1000];
            int n;
            long total = 0;
            while((n = file.read(b)) >= 0){
                outToClient.write(b,0,n);
                total += n;
            }

            file.close();
            outToClient.close();
            inFromClient.close();
        }
       
    }
Avatar billede arne_v Ekspert
29. september 2012 - 20:53 #4
Jeg tror at problemet ligger her:

        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        InputStream inFromServer2 = clientSocket.getInputStream();

En BufferedReader kan godt laese mere data fra den underliggende stream end det du faar ud via readLine.

Jeg tror at du mister data her.
Avatar billede arne_v Ekspert
29. september 2012 - 20:55 #5
Mit forslag:

drop bufferedReader og ideen med at sende linier

send tekst som en byte med laengde og saa bytes

og laes den som saadan (og brug String constructor til at faa en streng ud igen)
Avatar billede arne_v Ekspert
29. september 2012 - 20:55 #6
Og uanset hvad: drop DataOutputStream. Den ser saa tiltalende ud, men du boer kun bruge den til at skrive binaere int og double ud med.
Avatar billede Slettet bruger
29. september 2012 - 21:20 #7
Jeg har droppet DataOutputStream, men oplever stadig samme fejl.

Hvis man tæller hvor mange gange while() løkken kører i hhv. server og client, kører de ikke lige mange gange. F.eks. 177 for server og 160 for client ved et billede. Jeg bruger i øjeblikket følgende kode til selve filoverførslen:

Server:

OutputStream outToClient2 = s.getOutputStream();
            InputStream file = new FileInputStream(clientMessage);
            byte[] b = new byte[1000];
            int n;
            long total = 0;
            while((n = file.read(b)) >= 0){
                outToClient.write(b,0,n);
                total += n;
            }


Client:

InputStream inFromServer2 = clientSocket.getInputStream();
            int i = 1;
            String[] split = fileName.split("\\.");
            while(TCP.check_File_Exists(fileName) != 0){
                fileName = split[0] + i + "." + split[1];
                i++;
            }

            OutputStream file = new FileOutputStream(fileName);
            byte[] b = new byte[1000];
            int n;
            while((n = inFromServer2.read(b)) >= 0){
                file.write(b,0,n);
            }

Fejlen med både bufferedReader og DataOutputStream burde derfor være elimineret, men fejlen opstår stadig.
Avatar billede Slettet bruger
29. september 2012 - 21:24 #8
Det skal siges at hele filen nogle gange kommer over, og andre gange ikke.
Avatar billede arne_v Ekspert
29. september 2012 - 21:59 #9
Nu behoever while loekkerne ikke at koer det samme antal gange.

Du kan godt sende 3 + 10 + 7 bytes og laese 8 + 12 bytes med streams.

Det er antal bytes som er kritisk.
Avatar billede arne_v Ekspert
29. september 2012 - 21:59 #10
Mit forslag er stadig #4 og #5
Avatar billede Slettet bruger
29. september 2012 - 22:37 #11
Problemet blot at forslagene i #4 og #5 ikke har relation til selve filoverførslen, og de bør vel derfor ikke kunne på virke denne?
Avatar billede arne_v Ekspert
29. september 2012 - 22:43 #12
jo

hvis din BufferedReader laeser 100 bytes fra stream, du henter et filnavn paa 10 tegn og gaar i gang med at laese direkte, saa mangler du 90 bytes i starten af filen
Avatar billede arne_v Ekspert
30. september 2012 - 02:37 #13
Jeg poster lige noget kode til inspiration:

Det er muligt at du finder den overordnede konstruktion lidt funky, men logikken i selve metodern burde vaere synlig paa trods af dette.
Avatar billede arne_v Ekspert
30. september 2012 - 02:38 #14
Wrapper omkring Socket:


package clisrv;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class EnhancedSocket {
    public static interface Reader {
        public byte readByte() throws IOException;
        public byte[] readByteArray() throws IOException;
        public String readString() throws IOException;
        public InputStream readStream() throws IOException;
        public void close() throws IOException;
    }
    public static interface Writer {
        public void writeByte(byte b) throws IOException;
        public void writeByteArray(byte[] ba) throws IOException;
        public void writeString(String s) throws IOException;
        public void writeStream(InputStream is) throws IOException;
        public void close() throws IOException;
    }
    private static class ReaderImpl implements Reader {
        private InputStream is;
        public ReaderImpl(Socket s) throws IOException {
            is = s.getInputStream();
        }
        public byte readByte() throws IOException {
            return (byte)is.read();
        }
        public byte[] readByteArray() throws IOException {
            int len = is.read();
            byte[] ba = new byte[len];
            int ix = 0;
            while(ix < len) {
                ix += is.read(ba, ix, ba.length - ix);
            }
            return ba;
        }
        public String readString() throws IOException {
            byte[] ba = readByteArray();
            return new String(ba, "UTF-8");
        }
        public InputStream readStream() throws IOException {
            return is;
        }
        public void close() throws IOException {
            is.close();
        }
    }
    private static class WriterImpl implements Writer {
        private OutputStream os;
        public WriterImpl(Socket s) throws IOException {
            os = s.getOutputStream();
        }
        public void writeByte(byte b) throws IOException {
            os.write(b);
            os.flush();
        }
        public void writeByteArray(byte[] ba) throws IOException {
            if(ba.length > 255) throw new IllegalArgumentException("Byte array or string too long: " + ba.length);
            os.write(ba.length);
            os.write(ba);
            os.flush();
        }
        public void writeString(String s) throws IOException {
            writeByteArray(s.getBytes("UTF-8"));
        }
        public void writeStream(InputStream is) throws IOException {
            streamCopy(is, os);
        }
        public void close() throws IOException {
            os.close();
        }
    }
    public static Reader getReader(Socket s) throws IOException {
        return new ReaderImpl(s);
    }
    public static Writer getWriter(Socket s) throws IOException {
        return new WriterImpl(s);
    }
    public static void streamCopy(InputStream is, OutputStream os) throws IOException {
        byte[] ba = new byte[65536];
        int n;
        while((n = is.read(ba, 0, ba.length)) > 0) {
            os.write(ba, 0, n);
        }
        os.flush();
        is.close();
    }
}


Server:


package clisrv;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server1 {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(12345);
        Socket s = ss.accept();
        EnhancedSocket.Writer wrt = EnhancedSocket.getWriter(s);
        EnhancedSocket.Reader rdr = EnhancedSocket.getReader(s);
        String fnm = "C:/work/" + rdr.readString();
        if(new File(fnm).exists()) {
            wrt.writeString("OK");
            wrt.writeStream(new FileInputStream(fnm));
        } else {
            wrt.writeString("Error");
        }
        rdr.close();
        wrt.close();
    }
}


Client:


package clisrv;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class Client1 {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("localhost", 12345);
        EnhancedSocket.Writer wrt = EnhancedSocket.getWriter(s);
        EnhancedSocket.Reader rdr = EnhancedSocket.getReader(s);
        wrt.writeString("z1.zip");
        String sts = rdr.readString();
        if(sts.equals("OK")) {
            OutputStream f = new FileOutputStream("C:/work/z2.zip");
            EnhancedSocket.streamCopy(rdr.readStream(), f);
            f.close();
        }
        rdr.close();
        wrt.close();
    }
}
Avatar billede arne_v Ekspert
30. september 2012 - 02:40 #15
Man kan endda wrappe yderligere.

Extra wrapper omkring foersta wrapper:


package clisrv;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ExtraEnhancedSocket {
    public static interface Reader {
        public Object read() throws IOException;
        public void close() throws IOException;
    }
    public static interface Writer {
        public void write(Object o) throws IOException;
        public void close() throws IOException;
    }
    private static final byte BYTE = 1;
    private static final byte BYTE_ARRAY = 2;
    private static final byte STRING = 3;
    private static final byte STREAM = 4;
    private static class ReaderImpl implements Reader {
        private EnhancedSocket.Reader rdr;
        public ReaderImpl(Socket s) throws IOException {
            rdr = EnhancedSocket.getReader(s);
        }
        public Object read() throws IOException {
            byte typ = rdr.readByte();
            switch(typ) {
                case BYTE:
                    return rdr.readByte();
                case BYTE_ARRAY:
                    return rdr.readByteArray();
                case STRING:
                    return rdr.readString();
                case STREAM:
                    return rdr.readStream();
                default:
                    throw new IllegalStateException("Unknown type: " + typ);
            }
        }
        public void close() throws IOException {
            rdr.close();
        }
    }
    private static class WriterImpl implements Writer {
        private EnhancedSocket.Writer wrt;
        public WriterImpl(Socket s) throws IOException {
            wrt = EnhancedSocket.getWriter(s);
        }
        public void write(Object o) throws IOException {
            if(o instanceof Byte) {
                wrt.writeByte(BYTE);
                wrt.writeByte((Byte)o);
            } else if(o instanceof byte[]) {
                wrt.writeByte(BYTE_ARRAY);
                wrt.writeByteArray((byte[])o);
            } else if(o instanceof String) {
                wrt.writeByte(STRING);
                wrt.writeString((String)o);
            } else if(o instanceof InputStream) {
                wrt.writeByte(STREAM);
                wrt.writeStream((InputStream)o);
            } else {
                throw new IllegalArgumentException("Unknown type: " + o.getClass().getName());
            }
        }
        public void close() throws IOException {
            wrt.close();
        }
    }
    public static Reader getReader(Socket s) throws IOException {
        return new ReaderImpl(s);
    }
    public static Writer getWriter(Socket s) throws IOException {
        return new WriterImpl(s);
    }
    public static void streamCopy(InputStream is, OutputStream os) throws IOException {
        EnhancedSocket.streamCopy(is, os);
    }
}


Server:


package clisrv;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server2 {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(12345);
        Socket s = ss.accept();
        ExtraEnhancedSocket.Writer wrt = ExtraEnhancedSocket.getWriter(s);
        ExtraEnhancedSocket.Reader rdr = ExtraEnhancedSocket.getReader(s);
        String fnm = "C:/work/" + (String)rdr.read();
        if(new File(fnm).exists()) {
            wrt.write("OK");
            wrt.write(new FileInputStream(fnm));
        } else {
            wrt.write("Error");
        }
        rdr.close();
        wrt.close();
    }
}


Client:


package clisrv;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client2 {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("localhost", 12345);
        ExtraEnhancedSocket.Writer wrt = ExtraEnhancedSocket.getWriter(s);
        ExtraEnhancedSocket.Reader rdr = ExtraEnhancedSocket.getReader(s);
        wrt.write("z1.zip");
        String sts = (String)rdr.read();
        if(sts.equals("OK")) {
            OutputStream f = new FileOutputStream("C:/work/z2.zip");
            ExtraEnhancedSocket.streamCopy((InputStream)rdr.read(), f);
            f.close();
        }
        rdr.close();
        wrt.close();
    }
}
Avatar billede Slettet bruger
30. september 2012 - 07:32 #16
Hej Arne,

Tak for hjælpen, jeg tror det oprindelige spørgsmål længe er blevet besvaret - smid venligst svar.

Der går lige et par dage, før jeg får tid til at kigge på det igen.
Avatar billede arne_v Ekspert
30. september 2012 - 14:54 #17
svar
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