Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I reuse DatagramPacket without resetting the length

Tags:

java

udp

This came up while answering BufferedWriter only works the first time

As far as I understand the Java Doc (and this is confirmed by many posts on the net) a DatagramPacket should not accept more data than it's current size. The documentation for DatagramSocket.receive says

This method blocks until a datagram is received. The length field of the datagram packet object contains the length of the received message. If the message is longer than the packet's length, the message is truncated.

So, I made a program which reuses the receiving packet and send it longer and longer messages.

public class ReusePacket {

    private static class Sender implements Runnable {

        public void run() {
            try {
                DatagramSocket clientSocket = new DatagramSocket();
                byte[] buffer = "1234567890abcdefghijklmnopqrstuvwxyz".getBytes("US-ASCII");
                InetAddress address = InetAddress.getByName("127.0.0.1");

                for (int i = 1; i < buffer.length; i++) {
                    DatagramPacket mypacket = new DatagramPacket(buffer, i, address, 40000);
                    clientSocket.send(mypacket);
                    Thread.sleep(200);
                }                  
                System.exit(0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String args[]) throws Exception {
        DatagramSocket serverSock = new DatagramSocket(40000);
        byte[] buffer = new byte[100];
        DatagramPacket recievedPacket = new DatagramPacket(buffer, buffer.length);

        new Thread(new Sender()).start();

        while (true) {
            serverSock.receive(recievedPacket);
            String byteToString = new String(recievedPacket.getData(), 0, recievedPacket.getLength(), "US-ASCII");
            System.err.println("Length " + recievedPacket.getLength() + " data " + byteToString);
        }
    }
}

The output is

Length 1 data 1
Length 2 data 12
Length 3 data 123
Length 4 data 1234
Length 5 data 12345
Length 6 data 123456
...

So, even if the length is 1, in for the next receive it gets a message with length 2 and will not truncate it. However, if I manually set the length of the package then the message will be truncated to this length.

I have tested this on OSX 10.7.2 (Java 1.6.0_29) and Solaris 10 (Java 1.6.0_21). So to my questions.

Why does my code work and can expect it to work on other systems also?

To clarify, the behavior seems to have changed sometime in the past (at least for some JVMs), but I don't know if the old behavior was a bug. Am I lucky it works this way and should I expect it to work the same way on Oracle JVM, IBM JVM, JRockit, Android, AIX etc?

After further investigation and checking the source for 1.3.0, 1.3.1 and 1.4.0 the change was introduces in Sun implementation from 1.4.0, however, there is no mention of this in either the release notes or the network specific release notes of JDK 1.4.0.

like image 453
Roger Lindsjö Avatar asked Nov 30 '11 22:11

Roger Lindsjö


People also ask

What is the difference between DatagramPacket and DatagramSocket?

DatagramPacket object is the data container. DatagramSocket is the mechanism used to send or receive the DatagramPackets.

What is a DatagramPacket?

Datagram packets are used to implement a connectionless packet delivery service. Each message is routed from one machine to another based solely on information contained within that packet. Multiple packets sent from one machine to another might be routed differently, and might arrive in any order.


1 Answers

There are two different lengths here. The length of the packet is set to 100 in the constructor:

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

According to the docs, the length() method tells you the length of the message currently stored in the packet, which it does. Changing

byte[] buffer = new byte[100];

to

byte[] buffer = new byte[10];

yeilds the following output:

Length 1 data 1
Length 2 data 12
...
Length 9 data 123456789
Length 10 data 1234567890
Length 10 data 1234567890
Length 10 data 1234567890
...
like image 154
Thomas Avatar answered Sep 18 '22 07:09

Thomas