【问题标题】:Java - Download a file through browser using a SocketJava - 使用 Socket 通过浏览器下载文件
【发布时间】:2013-12-30 17:55:15
【问题描述】:

我正在学习 Java Socket,我尝试开发一个 Socket 使用端口 80 从浏览器下载文件。

所以,我运行我的主类(下面的源代码),它将在我想要的任何端口中打开一个Socket。 然后外面的人会访问http://MY_IP:MY_PORT/download/FILE_NAME

我得到了这一切,但是客户端的文件大小是 0 字节(对于小文件),对于更大的档案,大小略小(原始 600mb,下载 540mb+-)

我确实检查了很多次我的代码,我找不到任何错误,我也从 java libs 更改为 Apache-commons 认为它​​会有所帮助,但没有成功。

所以也许我认为我的响应标头有问题。

你们能帮帮我吗? 提前致谢。

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

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

}

【问题讨论】:

  • 嗯,你是要上传还是下载?您的 HTTPDownloaderThread 似乎正在尝试上传...虽然它也在尝试在发送请求之前从套接字读取,但这不会很好地工作...
  • @JonSkeet,客户端正在下载,我刚刚读过他的请求头。
  • @RemyLebeau,不重复,我正在尝试默认使用 Java 创建自己的服务器,不涉及其他库。

标签: java sockets http-headers download serversocket


【解决方案1】:

一方面,在标题和数据之间添加另一个“\r\n”。检查您的 HTTP 响应; Content-Length 标头是否报告下载文件的正确文件大小?文件是否以与服务器上相同的方式显示在客户端上可用? Web 代理总是有助于调试 HTTP(或其他客户端-服务器)应用程序:)

另外,我假设您在浏览器上指定端口 11000,因为这是您在服务器上监听的端口

【讨论】:

  • 另外,去掉Accept-Ranges: bytes 标头,因为代码实际上并不支持范围请求。并添加一个Connection: close 标头,因为服务器在发送文件后正在断开客户端。
  • @Joy Rê,谢谢,在标题和数据之间添加另一个“\r\n”使其按预期工作!其他一切正常。
【解决方案2】:

该网站不允许我发表评论,但我认为我应该告诉我我的发现......通过使用

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

会导致下载不完整或损坏,但如果仍要使用,则不能关闭 outStreamObj 和 socketObj 使用上述代码传输文件很快(至少根据我的观察)。如果您尝试关闭它将报告 Broken Pipe or Connection reset 或无法完成下载(冻结它)。

使用以下代码可以让您将 outStreamObj 作为 socketObj 关闭,但从套接字下载文件的速度很慢,可能是因为 while 循环。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多