2012-03-07 5 views
0

Я работаю над приложением TFTP-сервера. Мне удалось обработать успешную передачу файлов с сервера на клиент, но по-другому прослушивается.IndexOutOfBoundException при чтении файла

Клиент вместо передачи всего файла просто закончил компилятор whit, не возвращая ошибок. Отладчик показывает исключение IOBE в отмеченном коде, ссылаясь на то, что массив вне диапазона.

Весь процесс передачи идет так:

  1. Клиент передает имя файла и запрошенная операция WRQ - Написать запрос
  2. Сервер получил пакет и определяет операцию, если WRQ это дает новый файл соответствующее имя ,
  3. Сервер теперь начинает выполнение getData(), пока не получит пакет < 512 indicatorg EOT
  4. Клиент сохраняет данные, которые он считывает из файла.

Код ключа:

Клиент:

private void sendWRQ() throws Exception 
{ 
    String rrq = "WRQ-" + data; 
    outgoingData = rrq.getBytes(); 

    DatagramPacket output = new DatagramPacket(outgoingData, outgoingData.length, serverAddress, serverPort); 
    clientSocket.send(output); 
    //Thread.sleep(50); 
    sendData(); 
} 
byte outgoingData = new byte[512]; 
private void sendData() throws Exception 
{ 
    DatagramPacket dataTransfer = new DatagramPacket(outgoingData, outgoingData.length, serverAddress, serverPort); 
    InputStream fis = new FileInputStream(new File(data)); 

    int x; 
    while((x = fis.read(outgoingData,0,512)) != -1) // << Debugged gives IOBE 
    { 
     dataTransfer.setLength(x); 
     clientSocket.send(dataTransfer); 
     Thread.sleep(5); 
    } 

    fis.close(); 
} 

Сервер:

private void listen() throws Exception 
{ 
    DatagramPacket incTransfer = new DatagramPacket(incomingData, incomingData.length); 
    serverSocket.receive(incTransfer); 

    clientAddress = incTransfer.getAddress(); 
    clientPort = incTransfer.getPort(); 

    String output = new String(incTransfer.getData()); 
    if(output.substring(0, 3).equals("RRQ")) 
    { 
     File test = new File(output.substring(4)); 
     responseData = output.substring(4); 
     if(test.exists()) 
     { 
      sendResponse("Y"); 
     } else { 
      sendResponse("N"); 
     } 
    } else if (output.substring(0, 3).equals("WRQ")) 
    { 
     File test = new File(output.substring(4)); 
     if(test.exists()) 
     { 
      Calendar cal = Calendar.getInstance(); 
      SimpleDateFormat prefix = new SimpleDateFormat(date_format); 
      String date = prefix.format(cal.getTime()).toString(); 

      responseData = date + output.substring(4); 
      receiveData(); 
     } else { 
      responseData = output.substring(4); 
      receiveData(); 
     } 
    } 
} 


private void receiveData() throws Exception 
{ 
    DatagramPacket receiveData = new DatagramPacket(incomingData, incomingData.length); 
    OutputStream fos = new FileOutputStream(new File(responseData)); 

    while(true) 
    { 
     serverSocket.receive(receiveData); 
     if(receiveData.getLength() == 512) 
     { 
      fos.write(receiveData.getData()); 
     } else { 
      fos.write(receiveData.getData(), receiveData.getOffset(), receiveData.getLength()); 
      break; 
     } 
    } 
    fos.close(); 
} 
+0

напечатайте 'rrq.getBytes()' и посмотрите, правильно ли это. не уверен, что 'String' правильно обрабатывает специальные символы. – vulkanino

+0

Это правильно. проблема не здесь, эта часть отправляется и принимается, так как должна быть проблематичная часть, где я пометил ее в коде. –

+0

вы не указали определение 'outgoingData', у него достаточно места для хранения 512 байтов? – vulkanino

ответ

0

Единственный способ, который может произойти, если смещение или параметры длины нарушают ограничения, установленные для InputStream.read(byte[], int, int) ; в этом случае, вероятно, буфер не имеет длину 512 байт. В этом случае нет необходимости указывать 2-й третий параметр, просто опустите их, затем он станет read(buffer, 0, buffer.length) внутренне, что не может быть ошибкой.

0

Хорошо, так это кодируется, поле 'outgoingData' является:

1) инициализируется длиной 512

2) Затем, в sendWRQ(), 'outgoingData' является повторно инициализируется тем, что rrq.getBytes() отправляет обратно.

3) Затем в sendData() в качестве промежуточного буфера используется 'outgoingData', чтобы читать данные из файла и помещать его в объект dataTransfer.

Однако, поскольку «исходящие данные» повторно инициализируются на шаге 2, предположение на этапе №3, что «исходящие данные» по-прежнему составляет 512 байт, является ложным.

Так что, хотя EJP был прав, говоря, что использование read (outgoingData, 0, outgoingData.length()) будет работать, есть некоторые проблемы с архитектурой, которые, если вы обратитесь, вы очистите много потенциальных ошибок.

Например:

с кодом при условии, что нет, казалось бы, нет причин, чтобы outgoingData заявил на уровне класса и распределяется между двумя функциями. В зависимости от остальной части приложения это может стать проблемой Threading. Возможно, byte [] buffer = rrq.getBytes(); в sendWRQ() и байт [] buffer = новый байт [1024]; в sendData(). Кроме того, параметр «данные» находится на уровне класса .... по какой причине? Может быть лучше иметь возможность управления, если его значение передано в параметре.

И, наконец, мне повезло с помощью цикла do {} while() в сетевых ситуациях. Обеспечивает, что send() получает хотя бы один шанс отправить данные. И он сохраняет код более читаемым.

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