Dimitri
Dimitri

Reputation: 8290

Problem sending a file from a UDP server

I am writing a small UDP server in Java. When the server receives a command ('GET_VIDEO'), he reads a file ('video.raw') and then sends it to the client. My problem is that the number of bytes sent from the server is not equals to the number of bytes received in the client and my test failed. Here is the server code :

public class ServerMock {

public static void main(String[] args) throws Exception {

    byte[] buff = new byte[64];
    DatagramPacket packet = new DatagramPacket(buff, buff.length);
    DatagramSocket socket = new DatagramSocket(8080);

    System.out.println("Server started at 8080 ...");

    while (true) {
        socket.receive(packet);
        new ServerMock.ThreadVideo(socket, packet).run();

    }
}

public static class ThreadVideo implements Runnable {

    private DatagramPacket packet;
    private DatagramSocket socket;

    public ThreadVideo(DatagramSocket socket, DatagramPacket packet) {
        this.packet = packet;
        this.socket = socket;
    }

    public void run() {
        String cmd = new String(packet.getData(), 0, packet.getLength());
        if (cmd.equals("GET_VIDEO")) {
            try {
                read_and_send_video(this.packet.getAddress());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("S:Exiting ....");
            System.exit(0);
        }
    }


    private void read_and_send_video(InetAddress address)
            throws IOException {

        File file = new File("./video/video.raw");
        FileInputStream fis = new FileInputStream(file);
        DatagramPacket pack;

        int size = 0;
        byte[] buffer = new byte[64000];
        ByteBuffer bb = ByteBuffer.allocate(4);
        bb.order(ByteOrder.BIG_ENDIAN);

        while (true) {
            size = fis.read(buffer);
            System.out.println("Size = " + size);

            // Envoi du contenu du fichier
            pack = new DatagramPacket(buffer, buffer.length, address,
                    packet.getPort());
            socket.send(pack);
            if (size == -1) {
                break;
            }
        }

        String cmd = "END_VIDEO";
        pack = new DatagramPacket(cmd.getBytes(), cmd.getBytes().length,
                address, packet.getPort());
        socket.send(pack);

    }

}

}

Here is my client code :

public void client(int timeout, String message)
        throws SocketTimeoutException, SocketException {

    try {

        File file = new File("./video/tmp.raw");
        FileOutputStream fos = new FileOutputStream(file);
        File filein = new File("./video/video.raw");

        InetAddress address = InetAddress.getByName(host);
        byte[] data = message.getBytes();
        byte[] buffer = new byte[64000];

        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(timeout);

        DatagramPacket packet = new DatagramPacket(data, data.length,
                address, port);
        socket.send(packet);

        DatagramPacket rpacket = new DatagramPacket(buffer, buffer.length);

        while (true) {
            socket.receive(rpacket);
            if (rpacket.getLength() <= 9) {
                String cmd = new String(rpacket.getData(), 0,
                        rpacket.getLength());
                if (cmd.equals("END_VIDEO")) {
                    System.out.println("C:Fin de transmission");
                    break;
                }
            }
            fos.write(rpacket.getData());
        }

        System.out.println("video.raw ->" + filein.length());
        System.out.println("tmp.raw -> " + file.length());
        Assert.assertTrue(file.length() == filein.length());

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (UnknownHostException e) {

        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

Anyone can helps me with this problem. Some friend advises me to use the class ByteBuffer, ByteOrder but i don't know how to use them since I don't know how many bytes are really read when the server is reading the file. What's the best way to achieve that

Thanks

Upvotes: 0

Views: 3809

Answers (2)

Ullfoll
Ullfoll

Reputation: 163

I was searching for an example of sending a file from a udp server, and I found your question. You have to modify the following lines:

In the server:

    int size = 0;
    byte[] buffer = new byte[(int) file.length()];
    ByteBuffer bb = ByteBuffer.allocate(4);
    bb.order(ByteOrder.BIG_ENDIAN);

and also, you have to move the "socket.send(packet)":

while (true) {
size = fis.read(buffer);
System.out.println("Size = " + size);

// Envoi du contenu du fichier
pack = new DatagramPacket(buffer, buffer.length, address, packet.getPort());

if (size == -1) {
   break;
}

    socket.send(pack);
 }

In the client, modify fos.write(rpacket.getData()); with fos.write(rpacket.getData(), 0, rpacket.getLength());

Upvotes: 1

Erik
Erik

Reputation: 91320

UDP is unreliable, there is no guarantee whatsoever that you will receive all sent UDP packets, or that you will receive them in the order they were sent. You will need to tag each packet with a sequence number, you will need to reorder them on the client, you will need to tell the server when to slow down (or implement an acknowledgement mechanism), you will need the ability to ask for retransmission.

In short, unless the client is happy with lost and out-of-order packets (as most streaming clients are), you will need to reimplement TCP over UDP, or just use TCP.

Upvotes: 4

Related Questions