2013-12-18 3 views
1

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

SERVER КОД СТОРОНА:

public static void ReadAndWrite(byte[] aByte, Socket clientSocket, 
      InputStream inputStream, String fileOutput) 
        throws FileNotFoundException, IOException { 
     int bytesRead; 
     FileOutputStream fileOutputStream = null; 
     BufferedOutputStream bufferedOutputStream = null; 
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
     try 
     { 
     fileOutputStream = new FileOutputStream(fileOutput); 
     bufferedOutputStream = new BufferedOutputStream(fileOutputStream); 
     bytesRead = inputStream.read(aByte, 0, aByte.length); 
     System.out.println("The length is "+bytesRead); 
     int count = 0; 
     do { 
      count++; 
      byteArrayOutputStream.write(aByte); 
      bytesRead = inputStream.read(aByte); 
     } while (bytesRead != -1); 
     System.out.println("The count is "+count); 
     System.out.println("The length is "+byteArrayOutputStream.size()); 
     bufferedOutputStream.write(byteArrayOutputStream.toByteArray()); 
     bufferedOutputStream.flush(); 
     bufferedOutputStream.close(); 
     clientSocket.close(); 
     } 
     catch(Exception ex) 
     { 
      Logger.writeLog(ex,Listen.class.getName(), LogType.EXCEPTION); 
      throw ex; 
     } 

КЛИЕНТ SIDE КОД:

public void readByteArrayAndWriteToClientSocket(
      Socket connectionSocket, BufferedOutputStream outToClient, String fileToSend) throws Exception 
    { 
     try{ 
     if (outToClient != null) 
     { 
      File myFile = new File(fileToSend); 
      System.out.println(myFile.length()); 
      byte[] byteArray = new byte[(int) myFile.length()]; 

      FileInputStream fileInputStream = null; 

      try { 
       fileInputStream = new FileInputStream(myFile); 
      } catch (IOException ex) { 
       Logger.writeLog(ex, FileUtility.class.getName(), LogType.EXCEPTION); 
       throw ex; 
      } 
      BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); 

      try { 
       bufferedInputStream.read(byteArray, 0, byteArray.length); 
       outToClient.write(byteArray, 0, byteArray.length); 
       outToClient.flush(); 
       outToClient.close(); 
       connectionSocket.close(); 


       return; 
      } catch (IOException ex) { 
       Logger.writeLog(ex, FileUtility.class.getName(), LogType.EXCEPTION); 
       throw ex; 
      } 

     } 
     }catch (Exception e) { 
      Logger.writeLog(e, getClass().getName(), LogType.EXCEPTION); 
      throw e; 
     } 
    } 
+0

Код выглядит нормально. Если вы различаете файлы, где они разные? –

+2

Что вы подразумеваете под «потерей пакетов»? Часть данных не получена? Ни одна из данных не получена? Или, проверяя пакеты с чем-то вроде Wireshark, пакет упал? Иногда потери пакетов неизбежны по сравнению с любыми проводами с потерями; TCP был разработан с учетом этого и создает механизмы восстановления для обеспечения доставки (когда это возможно) и гарантирует порядок и целостность. –

+0

Вы не должны закрывать 'socket' сразу после отправки файла. Подождите несколько секунд перед завершением. Это гарантирует, что сервер действительно получит файл. –

ответ

3

Гнезда чтения метод будет возвращать, когда его получил все байты вы просили, или, когда он перестает получать данные из сети.

Поскольку передача часто прерывается в любой реальной сети, вам необходимо продолжать выполнять вызовы чтения до тех пор, пока вы не получите нужное количество байтов.

Вам нужно код что-то вроде этого:

 char [] buffer = new char[1024]; 
     int expect = 1000; 
     int sofar = 0; 
     int chars_read; 
     try 
     { 
      while((chars_read = from_server.read(buffer[sofar])) != -1) 
      { 
      sofar = sofar + chars_read; 
      if (sofar >= expected) break; 
      } 
     } 
     catch(IOException e) 
     { 
      to_user.println(e); 
     } 
+0

Ключ здесь - не игнорировать возвращаемое значение 'read'. 'read (buf, off, len)' не гарантирует, что он будет читать байты len'; он мог читать меньше. В любом случае он возвращает количество байтов, которые были фактически прочитаны. Это делается для чтения из файла и чтения из сокета. Guava ['ByteStreams.readFully (InputStream, byte [])'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/io/ByteStreams.html) ведет себя так, OP ожидает, что 'read' будет работать, хотя' ByteStreams.toByteArray() 'проще. –

+0

Как мне соответствовать этому существующему коду. Я не мог понять. – user3089869

+0

@James: Я заменил свой код своим. все еще сталкиваются с тем же вопросом – user3089869

3

Там нет «потеря пакетов», только ошибки в коде.

канонический способ скопировать поток в Java заключается в следующем:

while ((count = in.read(buffer)) > 0) 
{ 
    out.write(buffer, 0, count); 
} 

Если Вы знаете, количество байт заранее и отправитель должен держать соединение открытым после передачи, он становится:

while (total < expected && (count = in.read(buffer, 0, expected-total > buffer.length ? buffer.length : (int)(expected-total))) > 0) 
{ 
    out.write(buffer, 0, count); 
    total += count; 
} 

Забудьте обо всех ByteArrayInput/OutputStreams и дополнительных копиях. Просто прочитайте из файла и отправьте в сокет, или прочитайте из сокета и напишите в файл.

Смежные вопросы