Java通过FIO读取文件

时间:2012-03-07 00:04:50

标签: java sockets networking udp

我正在制作TFTP应用程序。根据协议RFC,所有数据必须以最大大小的512字节块发送。因此每个数据包可以是<= 512字节。

我将每个文件读入一个byte [] outgoingData = new byte [512];数组,我发送给客户端,但是当它获得一个总大小小于512字节的文件,如ascii文件或.ini,.css,.html等时,似乎出现了问题。

奇怪的是,对于UDP协议,每次传输高达3mb已经过去而没有大的损失。似乎发生的唯一损失是读取的文件的最后一个块少于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 个答案:

答案 0 :(得分:1)

您的数据包(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();
}

答案 1 :(得分:1)

    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) Method 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: 在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而客户端期待它,这似乎是你唯一的问题。第一个数据包目前没有为您服务。现在你只需要将ack数据包设置为你想要的。我刚发送它时它不包含字符串“ERROR”。