2013-08-01 1 views
1

Я хочу отправить несколько файлов с подключением к сокету. Для одного файла он отлично работает, но если я пытаюсь отправить более одного (по одному за раз) я получаю сокет исключение:отправить несколько файлов с помощью JAVA-сокета

java.net.SocketException: socket closed 

В общем мое соединение работает следующим образом:

  1. сервера ждет подключения
  2. Клиент подключается к серверу и посылает запрос на определенный файл (строка, которая содержит имя файла)
  3. сервер считывает локальный файл и отправляет его клиенту
  4. Client посылает другой запрос на другой файл и продолжается в точке 3.

вводный Метод «ожидания-для-запроса» -процедура выглядит следующим образом:

@Override 
    public void run() { 
     String message; 
     try { 
      while ((message = reader.readLine()) != null) { 

       if (message.equals(REQUESTKEY)) { 
        System.out.println("read files from directory and send back"); 
        sendStringToClient(createCodedDirContent(getFilesInDir(new File(DIR))),socket); 
       } else if (message.startsWith(FILE_PREFIX)) { 

        String filename = message.substring(FILE_PREFIX.length()); 
        try { 
         sendFile(new File(DIR+filename)); 
        } catch(IOException e) { 
         System.err.println("Error: Could not send File"); 
         e.printStackTrace(); 
        } 
       } else { 
        System.out.println("Key unknown!"); 
       } 
      } 
     } catch(Exception ex) { 

      ex.printStackTrace(); 
     } 

и метод моего SendFile() выглядит так:

public void sendFile(File file) throws IOException { 
     FileInputStream input = new FileInputStream(file); 
     OutputStream socketOut = socket.getOutputStream(); 

     System.out.println(file.getAbsolutePath()); 
     int read = 0; 
     while ((read = input.read()) != -1) { 
      socketOut.write(read); 
     } 
     socketOut.flush(); 

     System.out.println("File successfully sent!"); 

     input.close(); 
     socketOut.close(); 
    } 

Я думаю, что проблема кроется в socketOut.close(). К сожалению, метод также закрывает соединение сокета (проблема для дальнейших подключений). Но если я оставлю это закрытие, передача файлов не будет работать корректно: файлы становятся неполными на клиенте.

Как я могу избежать или исправить эту проблему? Или есть даже лучший способ передать несколько запрошенных файлов?

Спасибо

+2

Необходимо сообщить своему клиенту, насколько велики файлы. В противном случае вы просто потоки байтов без конца. Клиент не будет знать, когда прекратить чтение. Подумайте о связи между двумя (протокол). –

ответ

1

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

При чтении вы должны использовать DataInputStream и позвонить long len = dis.getLong(), а затем прочитать из потока байты len, а затем повторить для следующего файла. Вы можете счесть полезным отправить количество файлов в начале.

public void sendFile(File file, DataOutputStream dos) throws IOException { 
    if(dos!=null&&file.exists()&&file.isFile()) 
    { 
     FileInputStream input = new FileInputStream(file); 
     dos.writeLong(file.getLength()); 
     System.out.println(file.getAbsolutePath()); 
     int read = 0; 
     while ((read = input.read()) != -1) 
      dos.writeByte(read); 
     dos.flush(); 
     input.close(); 
     System.out.println("File successfully sent!"); 
    } 
} 
+0

Спасибо! Это то, что я хочу, теперь он работает :) – MS1

+0

Вопрос о отправке нескольких файлов через одно соединение сокета. Трудно видеть, как это квалифицируется как ответ. Это также крайне неэффективно. – EJP

+0

@EJP Если вы внимательно проверяете код, он закрывает 'FileInputStream', а не' DataOutputStream', поэтому я не уверен, как вы планируете писать более эффективный протокол (не дожидаясь сжатия файлов на лету) , Кроме того, 'DataOutputStream' построен с использованием метода' 'getOutputStream()') (https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getOutputStream()) из socket, лучше всего переходить на поток (IMO), чем продолжать его реконструировать. Так что я не уверен, в какой части их вопроса это не отвечает, особенно учитывая ответ авторов quesiton. – Robadob

0

Вы можете задать простой протокол между клиентом и сервером. Отправляйте длину файла перед содержимым файла. Используйте DataOutputStream/DataInputStream для отправки/чтения длины. Не закрывайте сокет после каждого файла.