IndexOutOfBoundException при чтении файла - PullRequest
0 голосов
/ 07 марта 2012

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

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

Весь процесс передачи выглядит следующим образом:

  1. Клиент передает имя файла и запрашиваемую операцию WRQ -Запрос на запись
  2. Сервер получил пакет и определяет операцию, если WRQ дает новому файлу соответствующее имя.
  3. Сервер теперь начинает выполнять receiveData (), пока не получит пакет <512 с указанием EOT </li>
  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();
}

Ответы [ 2 ]

0 голосов
/ 16 марта 2012

Хорошо, как это закодировано, поле 'outgoingData' имеет вид:

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

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

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

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

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

Например,:

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

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

0 голосов
/ 08 марта 2012

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

...