java - 基本 Java 文件服务器

标签 java sockets networking fileserver

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

首先,当我在本地主机上进行测试时,它可以正常工作,因为它可以传输 zip 文件,但是当我尝试打开它时,我收到有关文件已损坏的错误消息。这可能与 zip 文件格式或我如何传输它有关。

第二个问题是每当我使用本地主机以外的任何东西时它都会失败。我已经尝试将网站重定向到我的 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();
        }
        }
    }
    }
}

客户端代码片段,假设所有语法都是正确的,并且其他一切都存在并且可以工作,因为当我删除片段时我可能不匹配一些大括号或其他东西。

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 文件工作得很好,只有 .zip 会导致问题。

最佳答案

我在您的客户端上看到两个问题,这可能会导致问题:

您正在使用 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)——它也允许读取字符串,而不需要 Writer(和额外的缓冲)。

关于java - 基本 Java 文件服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4956608/

相关文章:

java - 以编程方式从关闭 Hook 访问退出状态

java - 无法将 JLabel 添加到 JPanel

java - 套接字,BufferedWriter.flush()不发送数据

c# - 写入文件仅在 "step in" Debug模式下有效?

networking - TCP 是否从一个间隔中随机选择一个时间来决定何时发生超时?

java - 如何在一个 TextView 中保留两个字符串的两种不同字体大小

java:关闭子进程标准流?

php - 如何加密非阻塞 PHP 套接字流?

sockets - 在 TCP 套接字上设置 SO_BROADCAST

javascript - 设置不同资源的优先级