2011-02-10 3 views
2

Я пытаюсь создать очень barebones файловый сервер, который ничего не делает, кроме загрузки zip-файла и выхода, но у меня проблемы. У меня две основные проблемы.Базовый Java Fileserver

Во-первых, когда я тестирую локальный хост, это работает, потому что он переносит 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(); 
     } 
     } 
    } 
    } 
} 

Client фрагмент кода, предположим, что все синтаксис является правильным, а все остальное существует и работает, потому что я, вероятно, несовпадающими некоторые скобки или что-то, когда я вырезать фрагмент из.

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

}

EDIT: Это прекрасно работает на локальном хосте с .doc и .docx файлов, это только .zip, что вызывает проблемы.

ответ

2

Я вижу две проблемы на вашем клиенте, которые могут вызвать проблемы:

Вы используете BufferedReader прочитать первую строку, а затем получить доступ к равнине, лежащей в основе InputStream из розетки с is.read(fileData);

Во-первых, BufferedReader (и это InputStreamReader) может читать больше, чем только первую строку на readLine() - остальное буферизуется для последующего поиска, но вы ничего не читаете. Таким образом, вам может не хватать начала вашего файла.

Во-вторых, у вас есть только один основной read для вашего сокета-InputStream, который может заполнять или не заполнять весь массив, так как вы не проверяете результат этого вызова метода. Таким образом, конец файла может состоять из нулевых байтов вместо реальных данных (и, конечно, будет столько нулевых байтов, сколько вы пропустили для первой проблемы). Вместо этого вы должны читать (а затем, возможно, мгновенно писать в файл) в цикле, проверяя (и добавляя) результаты чтения.

Edit: только для чтения в массив:

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

Существует readFully() метод DataInputStream, который делает именно это, я думаю. Если у вас есть большие файлы, вы не хотели бы его полностью в одном массиве, но читать и писать попеременно (с использованием меньшего массива в качестве буфера):

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

Я могу только догадываться, почему он работает с доком - сделали вы действительно сравниваете выходные файлы? Возможно, ваши документы Word меньше, чем ваш zip-файл, и, следовательно, вторая проблема действительно не применима, поскольку весь файл можно прочитать за один шаг.

То же самое (вторая) проблема применима и к вашему серверу для чтения файла.

Вы можете подумать об использовании DataInputStream (и DataOutputStream на стороне сервера) - он позволяет также считывать строки, без необходимости использования Writer (и дополнительной буферизации).

+0

Я думаю, что ты прав. Я просто сравнил шестнадцатеричные дампы двух ZIP-файлов. Они идентичны до позиции 0000FFF0, затем оригинал продолжается, пока копия заполняется пробелами. Кажется, что BufferedReader не влияет на него, начальные строки все одинаковы, но он не может прочитать весь файл. Не могли бы вы привести пример того, что я должен делать с циклом? –

+0

Я добавил пример моего ответа. –

+0

Спасибо. Теперь он может переносить zip. –

0

Вы пробовали его на своем внутреннем IP-адресе? Он также должен работать, и проблема будет только NAT или что-то вроде этого из Интернета.

Для вашего файла, являются ли md5sums одинаковыми?

+0

Я просто попробовал файл test.txt на своем внутреннем IP-адресе, и он отлично работал. Файлы test.txt имеют один и тот же md5, но zip-файлы имеют разные md5. Это очень запутанно. –

+0

Используйте шестнадцатеричный редактор, чтобы узнать, завершен ли файл, и если вы видите некоторые специальные символы из одного файла в другой (например, обертка char из java API) – Aif

0

Вы должны установить IP-адрес, который вы прослушиваете для своего IP-адреса LAN. Вы используете 127.0.0.1; который принимает запросы только от localhost.

+0

Я использую localhost только для тестирования. Когда я использую внешний IP-адрес, он не работает. –