简体   繁体   中英

Java - Download a file through browser using a Socket

i was studying Java Socket and i tried to develop a Socket using port 80 to download a file from browser.

So, i run my main class (source below), it will open a Socket in any port i want to. Then someone outside will access http://MY_IP:MY_PORT/download/FILE_NAME

I got this all working, however the filesize on client side is 0 bytes (for small files), and slightly lower size for bigger archives (original 600mb, download 540mb+-)

I really checked my code a lot of times, i couldn't find any error, i also changed from java libs to Apache-commons thinking it would help, but no success.

so maybe i think i got something wrong on Response headers.

Can you guys help me please? Thanks in advance.

Class HTTPDownload :

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

class HTTPDownloader {
    Socket incoming = null;
    ServerSocket server = null;

    public HTTPDownloader(){
        int port = 11000;

        try{
            server = new ServerSocket(port);
            System.out.println("Creating SocketServer on Port " + port);
        }catch(IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        System.out.println("Preparing to accept connections...");
        while(true){
            try{
                incoming = server.accept();
                System.out.println("connection!");
                HTTPDownloaderThread thread1 = new HTTPDownloaderThread(incoming);
                thread1.start();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String args[]) throws IOException{
        new HTTPDownloader();
    }
}

Class HTTPDownloadThread :

 import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Paths;

class HTTPDownloaderThread extends Thread {
    private static final int BUFFER_SIZE = 4096;
    private Socket socket;
    private byte[] buf = new byte[BUFFER_SIZE];
    private OutputStream out;
    private InputStream is;

    HTTPDownloaderThread(final Socket socket){
        this.socket = socket;
    }

    public void run(){
        int numberRead = 0;

        try{
            out = socket.getOutputStream();      
            is = socket.getInputStream();
            numberRead = is.read(buf, 0, BUFFER_SIZE);
            System.out.println("read " + numberRead);

            if(numberRead<0)
                return;

            byte[] readBuf = new byte[numberRead];
            System.arraycopy(buf, 0, readBuf, 0, numberRead);

            String header = new String(readBuf);
            System.out.println(header);
            String fileName = header.split("\r\n")[0].split(" ")[1].substring(1);
            System.out.println(socket.getInetAddress().getHostAddress()+" asked for file: "+fileName);

            File f = new File("C:\\TestFolder\\"+fileName);

            out.write("HTTP/1.1 200 OK\r\n".getBytes());
            out.write("Accept-Ranges: bytes\r\n".getBytes());
            out.write(("Content-Length: "+f.length()+"\r\n").getBytes());
            out.write("Content-Type: application/octet-stream\r\n".getBytes());
            out.write(("Content-Disposition: attachment; filename=\""+fileName+"\"\r\n").getBytes());
            out.write("\r\n".getBytes()); // Added as Joy Rê proposed, make it work!
            Files.copy(Paths.get("C:\\TestFolder\\"+fileName) , out);
            System.out.println("File upload completed!");
//          out.flush();
            out.close();
            socket.close();
        }catch(SocketException e) {
            System.out.println(e.getMessage());
        }catch(Exception e){
            e.printStackTrace();
        }
    }

}

For one thing, add another "\\r\\n" between headers and data. Check your HTTP Response; does the Content-Length header report the correct file size for the downloaded file? Do the files show up usable on the client in the same way they were on the server? Web proxies always helpful in debugging HTTP (or other client-server) applications :)

Also, I'm assuming you are specifying port 11000 on the browser, as that's what you're listening on on the server

The website does not let me to comment but i thought that I should tell about my findings.. By using

  Files.copy("path",outStreamObj);
  outStreamObj.close();
  socketObj.close();

Will cause incomplete or corrupt downloads but if still want to use then outStreamObj and socketObj must not be closed the files transfer is fast with the above code (atleast from my observation). If you try to close it will report Broken Pipe or Connection reset or will not complete the download(freeze it).

Instead using the following code will let you close the outStreamObj as socketObj but file download is slow from the socket probably because of while loop.

 Socket socket=serverSocket.accept();
 FileInputStream fs=new FileInputStream(path);
 OutputStream out = socket.getOutputStream();
 //This is the change from the Files.copy()
 int reads=0;
 while((reads=fs.read())!=-1)
        {
            out.write(reads);
        }
        out.close();
        socket.close();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM