为什么我可以重用DatagramPacket而不重置长度

时间:2011-11-30 22:22:02

标签: java udp

在回答BufferedWriter only works the first time

时出现了这个问题

据我所知,Java Doc(网上很多帖子证实了这一点),DatagramPacket不应该接受比当前大小更多的数据。 DatagramSocket.receive的文档说

  

此方法将一直阻塞,直到收到数据报。数据报包对象的长度字段包含接收消息的长度。如果消息长于数据包的长度,则消息将被截断。

所以,我制作了一个重用接收数据包的程序,并发送更长更长的消息。

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);
        }
    }
}

输出

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

因此,即使长度为1,对于下一次接收,它也会获得长度为2的消息,并且不会截断它。但是,如果我手动设置包的长度,则消息将被截断为此长度。

我在OSX 10.7.2(Java 1.6.0_29)和Solaris 10(Java 1.6.0_21)上测试了这个。所以我的问题。

为什么我的代码可以运行并且可以期望它在其他系统上运行?

澄清一下,这种行为似乎在过去的某个时候发生过变化(至少对于某些JVM而言),但我不知道旧的行为是否是一个错误。我很幸运它以这种方式工作,我是否应该期望它在Oracle JVM,IBM JVM,JRockit,Android,AIX等上以相同的方式工作?

在进一步调查并检查1.3.0,1.3.1和1.4.0的源代码之后,从1.4.0开始在Sun实现中引入了更改,但是在发行说明或网络中没有提到这一点。 JDK 1.4.0的特定发行说明。

1 个答案:

答案 0 :(得分:6)

这里有两种不同的长度。在构造函数中,数据包的长度设置为100:

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

根据文档,length()方法告诉您当前存储在数据包中的消息的长度。改变

byte[] buffer = new byte[100];

byte[] buffer = new byte[10];

提供以下输出:

Length 1 data 1
Length 2 data 12
...
Length 9 data 123456789
Length 10 data 1234567890
Length 10 data 1234567890
Length 10 data 1234567890
...