1

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();
        }
    }

}
Anon Achmed
  • 13
  • 1
  • 4
  • Um, are you trying to *upload* or *download*? Your `HTTPDownloaderThread` appears to be trying to upload... although it's also trying to read from the socket before it sends a request, which isn't going to work well... – Jon Skeet Dec 30 '13 at 17:57
  • possible duplicate of [Create a simple HTTP server with Java?](http://stackoverflow.com/questions/2717294/create-a-simple-http-server-with-java) – Remy Lebeau Dec 30 '13 at 19:11
  • @JonSkeet, the Client is downloading, i just read his header request before. – Anon Achmed Jan 02 '14 at 10:22
  • @RemyLebeau, not duplicated, i am trying to create my own server using Java by default, no other libs involved. – Anon Achmed Jan 02 '14 at 10:23

2 Answers2

2

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

Joy Rê
  • 159
  • 4
  • Also, get rid of the `Accept-Ranges: bytes` header since the code does not actually support ranged requests. And add a `Connection: close` header since the server is disconnecting the client after sending the file. – Remy Lebeau Dec 30 '13 at 19:09
  • @Joy Rê, thanks, adding another "\r\n" between headers and data make it work as expected! Everything else was working fine. – Anon Achmed Jan 02 '14 at 10:24
0

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();
Newbee
  • 45
  • 1
  • 9