3

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.

Here is my code :

public class ServeurBouchon {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

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

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

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

    }

    public static class ThreadVideo extends Thread {

        private DatagramSocket socket;
        private DatagramPacket packet;

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

        public void run() {
            String cmd = new String(packet.getData(), 0, packet.getLength());
            System.out.println("S:CMD reçu :" + cmd);
            if ("GET_VIDEO".equals(cmd)) {
                read_and_send_video(this.packet.getAddress());
            } else if ("TIMEOUT_REQUEST".equals(cmd)) {
                return;
            } else {
                System.out.println(" Exiting ...");
                return;
            }
            System.out.println("Fin .....");
        }

        private void read_and_send_video(InetAddress address) {
            System.out.println(" reading and sending video ...");
            File file = new File("./video/video.raw");
            ByteBuffer ibb = ByteBuffer.allocate(4);
            ibb.order(ByteOrder.BIG_ENDIAN);

            FileInputStream fis = null;
            DatagramPacket pack;
            byte[] buff = new byte[4];
            System.out.println(" Sending ...");
            try {
                fis = new FileInputStream(file);
                int size = 0;
                while ( size != -1) {
                    size = fis.read(buff, 0, buff.length);
                    System.out.println(" size = " + size);
                    ibb.put(buff);                  
                    System.out.println("Size : " + ibb.getInt());
                    int length = ibb.getInt();
                    byte[] fbuff = new byte[length];                    
                    fis.read(fbuff, 0, length);

                    pack = new DatagramPacket(fbuff, fbuff.length, address,
                            packet.getPort());
                    socket.send(pack);
                }

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

        }
    }

}

The raw file format is a continuous of "size + frame". The "size" variable contains the size(an int) of the next frame to be read. My problem is when I am reading the file(in the line ibb.getInt()), I get this exception :

Exception in thread "main" java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:480)
at java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:336)
at fr.sar.dss.bouchon.ServeurBouchon$ThreadVideo.read_and_send_video(ServeurBouchon.java:75)
at fr.sar.dss.bouchon.ServeurBouchon$ThreadVideo.run(ServeurBouchon.java:48)
at fr.sar.dss.bouchon.ServeurBouchon.main(ServeurBouchon.java:29)

Maybe I am doing this wrong but can somebody tells me where is my mistake?

Thansk for your help ;)

Daniel
  • 27,718
  • 20
  • 89
  • 133
Dimitri
  • 8,122
  • 19
  • 71
  • 128

2 Answers2

16

This reads two ints.

System.out.println("Size : " + ibb.getInt());
int length = ibb.getInt();

Use this:

int length = ibb.getInt();
System.out.println("Size : " + length);
Erik
  • 88,732
  • 13
  • 198
  • 189
-3

I finally find the answer to my problem. Everytime you use the class ByteBuffer and his access method (like getInt(), getShort(), getFloat(), array()), you should call the method rewind to set the current buffer position to zero. This code totally works :

    System.out.println("Size : " + ibb.getInt());
    ibb.rewind();
    int length = ibb.getInt();
    ibb.rewind();

Thx for your help

Dimitri
  • 8,122
  • 19
  • 71
  • 128
  • 2
    You shouldn't use rewind. You should be aware in your code that you are advancing the byte buffer's current marker each time you `get` something and read the value you need only once. – Zoltán Apr 30 '13 at 14:37
  • 1
    This answer seems to be missing the point. Methods like getInt() don't simply return a value in the typical getter sense. Instead, they return the value at the buffer's current position and advance to the next. Rewinding may work (as you've found) but what if the previous position was overwritten in between your calls to getInt() and rewind()? If you simply want to use the value that was read more than once, why wouldn't you just save it to a local variable. – spaaarky21 Jun 10 '13 at 18:41
  • for me `rewind()` helped in solving the problem. – Akhil Jain Jul 23 '14 at 09:28