Java читает файлы через FIO - PullRequest
1 голос
/ 07 марта 2012

Я делаю заявку TFTP. В соответствии с протоколами RFC все данные должны передаваться кусками по 512 байт в максимальном размере. Таким образом, каждый пакет может быть <= 512 байт. </p>

Я читаю каждый файл в байте [] outgoingData = new byte [512]; массив, и я отправляю его клиенту, однако, кажется, что что-то идет не так, когда получается файл, размер которого меньше 512 байт, например файл ascii или .ini, .css, .html и т. д.

Как ни странно, для протокола UDP каждая передача до 3 МБ прошла без больших потерь. Единственная потеря, которая, по-видимому, происходит, - это когда последний фрагмент файла считывается менее 512 байт.

private void sendData() throws Exception
{
    DatagramPacket data = new DatagramPacket(outgoingData, outgoingData.length, clientAddress, clientPort);
    InputStream fis = new FileInputStream(responseData);

    int a;
    while((a = fis.read(outgoingData,0,512)) != -1)
    {
        serverSocket.send(data);
        Thread.sleep(5);
    }
}

Так как это проблема, связанная с чтением файла, как я могу исправить потерю в конце файла и проблему, когда он не читает файл, размер которого меньше 512

Клиент:

private void receiveData() throws Exception
{
    DatagramPacket receiveData = new DatagramPacket(incomingData, incomingData.length);
    OutputStream fos = new FileOutputStream(new File("1"+data));
    while(true)
    {
        clientSocket.receive(receiveData);
        if(receiveData.getLength() == 512)
        {
            fos.write(incomingData);xx
        } else {
            fos.write(incomingData);
            fos.close();
            break;
        }
    }
    clientSocket.close();
}

Ответы [ 2 ]

1 голос
/ 07 марта 2012
    private void sendData() throws Exception
{
    DatagramPacket data = new DatagramPacket(outgoingData, outgoingData.length, clientAddress, clientPort);
    InputStream fis = new FileInputStream(responseData);

    int a;
    while((a = fis.read(outgoingData,0,512)) != -1)
    {
        data.setLength(a); //'a' is the number of bytes read setLength(int) lets you set the length of bytes you want to sent
        serverSocket.send(data);
        Thread.sleep(5);
    }
}

setLength (int) Метод DatagramPacket на приемном конце вы делаете что-то вроде этого:

byte[]buffer = new byte[512];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
while(socket.isBound() && !socket.isClosed()){
    socket.receive(packet);
    system.out.println("Packet Length: "+packet.getLength());
    //code here
}

FIX: IN Server.java

private void sendResponse(String res) throws Exception
        {
            if(res.equals("Y"))
            {
                // Send ACK -> Send File
                DatagramPacket x = new DatagramPacket(outgoingData, outgoingData.length, clientAddress, clientPort);
                serverSocket.send(x); //<<SEND ACK
                sendData();
            } else {
                String error = "ERROR: The file you requested does not exist.";
                outgoingData = error.getBytes();
                DatagramPacket err = new DatagramPacket(outgoingData, outgoingData.length, clientAddress, clientPort);

                serverSocket.send(err);
            }
        }

Я заметил, что вы не отправляете подтверждение, а клиент ожидает его, и это, похоже, ваша единственная проблема. первый пакет в настоящее время ничего не делает для вас. теперь вам просто нужно установить пакет ack на то, что вы хотите. Я только что отправил его, пока в нем нет строки «ОШИБКА».

1 голос
/ 07 марта 2012

Ваш пакет (data) имеет фиксированную длину outgoingData.length (512?) Прямо сейчас.Поэтому, когда вы вызываете serverSocket.send(data), он отправляет все данные в массиве outgoingData.

Проблема в том, что fis.read(outgoingData, 0, 512) иногда читает менее 512 байтов данных.Скорее всего, это произойдет в конце потока ввода файла, когда осталось не так много данных для чтения.Но это также может произойти и раньше (на практике это маловероятно, но вы все равно должны проверить безопасность).

Вы уже сохранили количество байтов, которое фактически читается в a.Просто передайте это число setLength, чтобы DatagramSocket знал, что нужно отправить только столько данных.

Это должно помочь:

private void sendData() throws Exception
{
    DatagramPacket data = new DatagramPacket(outgoingData, outgoingData.length, clientAddress, clientPort);
    InputStream fis = new FileInputStream(responseData);

    int a;
    while((a = fis.read(outgoingData,0,512)) != -1)
    {
        data.setLength(a);
        // or this
        //data = new DatagramPacket(outgoingData, a, clientAddress, clientPort);

        serverSocket.send(data);
        Thread.sleep(5);
    }
}

Для получения:

private void receiveData() throws Exception {
    DatagramPacket receiveData = new DatagramPacket(new byte[512], 512);
    OutputStream fos = new FileOutputStream(new File("1"+data));
    while (true) {
        clientSocket.receive(receiveData);
        if (receiveData.getLength() == 512) {
            fos.write(receiveData.getData());
        } else {
            fos.write(receiveData.getData(), receiveData.getOffset(), receiveData.getLength());
            break;
        }
    }
    fos.close();
    clientSocket.close();
}
...