我正在尝试创建一个非常简单的文件服务器,它只做下载一个 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);
首先,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/