【问题标题】:Basic Java Fileserver基本 Java 文件服务器
【发布时间】:2011-06-24 19:18:29
【问题描述】:

我正在尝试创建一个非常简单的文件服务器,它只会下载一个 zip 文件并退出,但我遇到了问题。我有两个主要问题。

首先,当我在 localhost 上进行测试时,它可以正常工作,因为它传输了 zip 文件,但是当我尝试打开它时,我收到一个错误,提示它已损坏。这可能与 zip 文件格式或我的传输方式有关。

第二个问题是当我使用除 localhost 之外的任何东西时它都会失败。我尝试将网站重定向到我的 IP,然后输入我的 IP 地址,但都失败了,即使我关闭了所有防火墙和防病毒软件。

服务器代码:

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

public class FileServer {
    public static void main(String[] args) throws IOException {
    final int PORT_NUMBER = 44444;
    ServerSocket serverSock = null;
    PrintWriter out = null;
    BufferedInputStream bin = null;
    OutputStream os = null;
    Socket clientSock = null;
    File file;
    byte[] fileData;
    String filename = "file.zip";

    while(true) {
        try {
        //Listen on port
        serverSock = new ServerSocket(PORT_NUMBER);

        //Get connection
        clientSock = serverSock.accept();
        System.out.println("Connected client");

        //Get output stream
        out = new PrintWriter(clientSock.getOutputStream(), true);

        out.println(filename);    //Print filename
        file = new File(filename); //Get file
        fileData = new byte[(int)file.length()]; //Stores the file data
        bin = new BufferedInputStream(new FileInputStream(file));
        out.println((int)file.length()); //Print filesize
        bin.read(fileData); //Read contents of file
        os = clientSock.getOutputStream();
        os.write(fileData); //Write the file data
        os.flush();
        } catch(SocketException e) {
        System.out.println("Client disconnected");
        } catch(Exception e) {
        System.out.println(e.getMessage());
        System.exit(1);
        } finally {
        //Close all connections
        System.out.println("Shutting down");

        if(os != null) {
            os.close();
        }

        if(bin != null) {
            bin.close();
        }

        if(out != null) {
            out.close();
        }

        if(clientSock != null) {
            clientSock.close();
        }

        if(serverSock != null) {
            serverSock.close();
        }
        }
    }
    }
}

客户端代码 sn-p,假设所有语法都是正确的,并且其他所有内容都存在并且可以正常工作,因为我在删除 sn-p 时可能不匹配一些大括号之类的东西。

import java.io.*;
import java.net.*;
import javax.swing.JOptionPane;

public static void main(String[] args) {
        final int PORT_NUMBER = 44444;
        final String HOSTNAME = "127.0.0.1";
        String filename = "default.txt";
        Socket sock = null;
        BufferedReader in = null;
        BufferedOutputStream bos = null;
        InputStream is = null;
        byte[] fileData;

        //Attempt to connect
        try {
        sock = new Socket(HOSTNAME, PORT_NUMBER);
        in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        is = sock.getInputStream();
        } catch(UnknownHostException e) {
        JOptionPane.showMessageDialog(this, "Error: could not connect to host " + HOSTNAME + " on port number " + PORT_NUMBER);
        System.exit(1);
        } catch(ConnectException e) {
        JOptionPane.showMessageDialog(this, "Error: connection refused");
        System.exit(1);
        } catch(Exception e) {
        JOptionPane.showMessageDialog(this, e);
        System.exit(1);
        }

        try {
        filename = in.readLine();
        bos = new BufferedOutputStream(new FileOutputStream(filename));
        fileData = new byte[Integer.decode(in.readLine())]; //Gets file size
        is.read(fileData);
        bos.write(fileData);
        bos.flush();
        bos.close();

        if(is != null) {
            is.close();
        }

        if(in != null) {
            in.close();
        }

        if(bos != null) {
            bos.close();
        }

        if(sock != null) {
            sock.close();
        }
        } catch(Exception e) {
        JOptionPane.showMessageDialog(this, e);
        System.exit(1);
        }

        JOptionPane.showMessageDialog(this, "Download complete");
    }
    }
    }                                        

}

编辑:它在带有 .doc 和 .docx 文件的 localhost 上工作得很好,只有 .zip 会导致问题。

【问题讨论】:

    标签: java sockets networking fileserver


    【解决方案1】:

    您是否在内部 IP 上尝试过?它也应该可以工作,问题只是 NAT 或来自互联网的类似问题。

    对于您的文件,md5sum 是否相同?

    【讨论】:

    • 我刚刚在我的内部 IP 上尝试了一个 test.txt 文件,它运行良好。 test.txt 文件具有相同的 md5,但 zip 文件具有不同的 md5。这非常令人困惑。
    • 使用十六进制编辑器查看文件是否完整,以及是否看到从一个文件到另一个文件的一些特殊字符(例如来自 java API 的包装器字符)
    【解决方案2】:

    您应该将您正在收听的 IP 设置为您的 LAN IP。您正在使用127.0.0.1;它只接受来自本地主机的请求。

    【讨论】:

    • 我只使用 localhost 进行测试。当我使用我的外部 IP 时,它不起作用。
    【解决方案3】:

    我发现您的客户端有两个问题,可能会导致问题:

    您正在使用BufferedReader 读取第一行,然后使用is.read(fileData); 从套接字访问普通的底层 InputStream

    首先,BufferedReader(它是 InputStreamReader)可能读取的不仅仅是readLine() 上的第一行 - 其余部分被缓冲以供以后检索,但您不会再读取任何内容。因此,您可能会丢失文件的开头。

    其次,您的 socket-InputStream 只有一个主要的read,它可能会或可能不会填充整个数组,因为您不检查此方法调用的结果。因此,文件的结尾可能由零字节组成,而不是真实数据(当然,零字节与您在第一个问题中遗漏的一样多)。您应该改为循环读取(然后可能立即写入文件),检查(并添加)读取调用的结果。

    编辑: 只读入数组:

    int read = 0;
    while(read < size) {
        int r = is.read(fileData, read, size-read);
        if(r < 0) {
           // end of file, should not occur if noone interrupts your stream or such
           throw new EOFException("input ended prematurely");
        }
        read += r;
    }
    

    我认为DataInputStream 中有一个readFully() 方法可以做到这一点。 如果你有更大的文件,你不希望它完全在一个数组中,而是交替读取和写入(使用较小的数组作为缓冲区):

    InputStream is = ...;
    int len = ...;
    OutputStream out = ...;
    
    int read = 0;
    byte[] buf = new byte[8000];
    while(read < len) {
        int r = is.read(buf);
        if(r < 0) {
           // end of file, should not occur if noone interrupts your stream or such
           throw new EOFException("input ended prematurely");
        }
        out.write(buf, 0, r);
        read += r;
    }
    

    我只能推测为什么它适用于 doc - 你真的比较了输出文件吗?也许您的 Word 文档比您的 zip 文件小,因此第二个问题并不真正适用,因为可以一步读取所有文件。

    同样的(第二个)问题实际上也适用于您的服务器读取文件。

    您可能会考虑使用 DataInputStream(和服务器端的 DataOutputStream) - 它也允许读取字符串,而无需写入器(和额外的缓冲)。

    【讨论】:

    • 我认为你是对的。我只是比较了两个 zip 文件的十六进制转储。它们在位置 0000FFF0 之前是相同的,然后原件继续,而副本填充空白。似乎 BufferedReader 不影响它,开始的行都是一样的,但它无法读取整个文件。你能提供一个我应该用循环做什么的例子吗?
    • 我在答案中添加了一个示例。
    • 谢谢。它现在可以传输 zip。
    猜你喜欢
    • 2011-11-08
    • 2010-11-03
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    相关资源
    最近更新 更多