如何重新初始化一个分组的缓冲器? [英] How to reinitialize the buffer of a packet?

查看:168
本文介绍了如何重新初始化一个分组的缓冲器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些问题,当我把从netcat的还是我的客户的UDP数据包到我这监听广播UDP数据包UDP服务器。问题是,我不能reinitilize socket.receive的缓冲器(数据包); 键,当你检查我的控制台输出,你会看到,在报文的发送或接收两次甚至更多次和最讨厌的是就是:当我发送具有更大的长度第一,下一个是小由previous 的一部分! (问题都标有位置上的控制台输出)我的客户端和服务器都位于相同的局域网上。

I am having some problem while I am sending UDP packets from netcat or my client to my UDP server which listens for broadcast UDP packets. The problem is that I can't reinitilize the buffer of socket.receive(packet); And as you check my console output you will see that the packets are sent or received twice or even more times and most annoying of all is that when I send a packet with greater length first, the next one which is smaller consists part of the previous! (Problems are marked with HERE on the console output) My Client and Server are located on the same LAN.

客户端code:

DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(true);
byte[] buf = ("Hello from Client").getBytes();
byte[] buf2 = ("omg").getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, getBroadcastAddress(UDPConnection.context), Server.SERVERPORT);
DatagramPacket packet2 = new DatagramPacket(buf2, buf2.length, getBroadcastAddress(UDPConnection.context), Server.SERVERPORT);
Log.d("UDP", "C: Sending: '" + new String(buf) + "'");
socket.send(packet);
socket.send(packet2);

服务器code:

Server code:

void run(){
MulticastSocket socket = new MulticastSocket(SERVERPORT);
socket.setBroadcast(true);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while(true){
    Log.d("UDP", "S: Receiving...");
    socket.receive(packet);
    //socket.setReceiveBufferSize(buf.length);
    packet.setData(buf);
    Log.i("BUFFER_packet",packet.getLength()+"");
    Log.i("BUFFER_socket",socket.getReceiveBufferSize()+"");
    Log.d("UDP", "S: From: " + packet.getAddress().getHostAddress());
    Log.d("UDP", "S: Received: "+getRidOfAnnoyingChar(packet));
    Log.d("UDP", "S: Done.");
}
}
    //this method is getting rid of the "questionmark in a black diamond" character
    public String getRidOfAnnoyingChar(DatagramPacket packet){
        Log.i("UDP","Inside getridofannoyingchar method.");
        String result = new String(packet.getData());
        char[] annoyingchar = new char[1];
        char[] charresult = result.toCharArray();
        result = "";
        for(int i=0;i<charresult.length;i++){
            if(charresult[i]==annoyingchar[0]){
                break;
            }
            result+=charresult[i];
        }
        return result;
    }

控制台:

11-27 18:15:27.515: D/UDP(15242): S: Connecting...
11-27 18:15:27.519: I/ServerIP(15242): ::
11-27 18:15:27.519: I/LocalIP(15242): 192.168.0.4
11-27 18:15:27.523: D/UDP(15242): S: Receiving...
11-27 18:15:28.031: D/UDP(15242): C: Connecting...
11-27 18:15:28.039: I/BroadcastIP(15242): 192.168.0.255
11-27 18:15:28.042: I/BroadcastIP(15242): 192.168.0.255
11-27 18:15:28.070: D/UDP(15242): C: Sending: 'Hello from Client'
11-27 18:15:28.074: I/BUFFER_packet(15242): 1024
11-27 18:15:28.074: I/BUFFER_socket(15242): 110592
11-27 18:15:28.074: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.074: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.078: I/BUFFER_packet(15242): 1024
11-27 18:15:28.078: I/BUFFER_socket(15242): 110592
11-27 18:15:28.078: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.078: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.085: D/UDP(15242): S: Received: Hello from Client <------------HERE
11-27 18:15:28.085: D/UDP(15242): S: Done.
11-27 18:15:28.085: D/UDP(15242): S: Receiving...
11-27 18:15:28.085: D/UDP(15242): S: Received: Hello from Client <------------HERE
11-27 18:15:28.085: D/UDP(15242): S: Done.
11-27 18:15:28.085: D/UDP(15242): S: Receiving...
11-27 18:15:28.085: I/BUFFER_packet(15242): 1024
11-27 18:15:28.085: I/BUFFER_socket(15242): 110592
11-27 18:15:28.085: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.085: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.089: D/UDP(15242): S: Received: omglo from Client <------------HERE
11-27 18:15:28.089: D/UDP(15242): S: Done.
11-27 18:15:28.089: D/UDP(15242): S: Receiving...
11-27 18:15:28.089: I/BUFFER_packet(15242): 1024
11-27 18:15:28.089: I/BUFFER_socket(15242): 110592
11-27 18:15:28.089: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.089: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.089: D/UDP(15242): S: Received: omglo from Client <------------HERE
11-27 18:15:28.089: D/UDP(15242): S: Done.
11-27 18:15:28.089: D/UDP(15242): S: Receiving...
11-27 18:15:28.089: D/UDP(15242): C: Sent.
11-27 18:15:28.089: D/UDP(15242): C: Done.

任何帮助将是非常美联社preciated! :)

Any help will be highly appreciated! :)

PS。有可能是在像完成/发送/连接/接收控制台未添加到我的样本code,但一些输出所有的接收:/ BUFFER_packet / _socket /起价为present

PS. there might be some outputs in the console like Done/Sent/Connecting/Receiving that are not added to my sample code but all the Received:/BUFFER_packet/_socket/From are present.

推荐答案

您不必重新初始化缓冲区的数据包,你只需要重置缓冲区不管他们最初的内容(也就是你需要填写接收阵列零)。

you don't need to reinitialize the buffer in the packet, you just need to reset the contents of the buffer to whatever they were initially (i.e. you need to fill the receiving array with zeroes).

的呼叫:

Arrays.fill(BUF(字节)0)

Arrays.fill(buf,(byte)0);

在服务器端将重置阵列零,因为在Java中数组传递按引用不能通过按值(也就是你有引用数组的内容是相同的参考,该DatagramPacket的了,这样你就可以修改它,而无需通过DatagramPacket的方法)。

on the server side will reset the array to zeroes since arrays in Java are pass-by-reference not pass-by-value (i.e. the reference you have to the array contents is the same as the reference that the DatagramPacket has, so you can modify it without going through DatagramPacket methods).

说了这么多,你正在连载的方式/ deserialising数据并不理想。你会过得更好使用一个ByteArrayOutputStream和ByteArrayInputStream的缠在发送和接收缓冲区,然后使用DataOutputStream /包裹的DataInputStream围绕这些。这将允许你写和读的字符串中这将可能存储的字符串,以便在缓冲区中的所有剩余的数据将被忽略反正的长度以及定义的格式。正确连载/ deserialising以这种方式也将不再需要剥离的黑钻石的性格。

Having said that the way you are serialising/deserialising the data isn't ideal. You would be better off using a ByteArrayOutputStream and ByteArrayInputStream wrapped around the sending and receiving buffers, and then a DataOutputStream / DataInputStream wrapped around those. These would allow you to write and read the string in a well defined format which would likely store the length of the string so that any remaining data on the buffer would be ignored anyway. Properly serialising / deserialising in this way would also remove the need to strip the 'black diamond' character.

<一个href="http://docs.oracle.com/javase/1.4.2/docs/api/java/io/DataOutputStream.html#writeUTF%28java.lang.String%29"相对=nofollow> DataOutputStream.writeUTF

如果您有兴趣这样做的原因是,与你使用java.lang.String中的默认的序列化(的GetBytes()和新的字符串(字节[])),以及如何UDP包被填充。我会尽力熬下来的关键位:

If you're interested in the reasoning behind this it is to do with your use of java.lang.String's default serialisation (getBytes() and new String(byte[])) and how the UDP packet is being populated. I'll try and boil it down to the crucial bits:

Java的内部重新presentation为String对象不是一个字节数组 - 它的字符数组。爪哇字符是不一样的字节 - 一个字符实际上是2字节,因为它需要能够重新present不仅仅是拉丁字母(ACBD ...),它需要支持其他字符其它语言/文化就像从西里尔字母,汉字等,一个字节的东西是不够的(一个字节可以让你256的可能性,2个字节可以让你65536的可能性)。

Java's internal representation for String objects is not a byte array - its a char array. Java chars are not the same as bytes - one char is actually 2 bytes because it needs to be able to represent more than just the latin alphabet (acbd...), it needs to support other characters from other languages/cultures like stuff from Cyrillic, Kanji etc and one byte isn't enough (one byte gets you 256 possibilities, 2 bytes gets you 65536 possibilities).

由于当你调用getBytes()构造Java有使用一些'计划'(编码),把该字符数组转换为字节数组(序列化)的结果。详情为何不事太多,但是当你发送字节的第一块,(可以说,它的10个字节),你读了包成一个更大的缓冲区(1024字节)。然后你问的Java String要deserialise是整个缓冲区,而不仅仅是10个字节。

As a result when you call getBytes() Java has to use some 'scheme' (encoding) to turn that character array into a byte array (serialisation). The details of that don't matter too much, but when you send the first chunk of bytes, (lets say its 10 bytes long) you read the packet into a much bigger buffer (1024 bytes). Then you ask Java String to deserialise that entire buffer, not just the 10 bytes.

该计划(编码)不知道,只处理前10个字节,因此它试图去code整个1024字节,然后你会得到你的字符串,如黑钻,或怪异字符(在那里你通过发送你好),你从previous字符接收混合到您的字符串把一些其他数据的10个字节后。

The scheme (encoding) doesn't know to only deal with the first 10 bytes so it tries to decode the whole 1024 bytes, and then you get weird characters on your string like the black diamond, or (where you've put some other data after the 10 bytes by sending 'hello') you get characters from the previous receive mixed into your string.

使用写/的readUTF会写字节数组,以及数据的长度,所以当你读一遍就知道它只有读前10个字符(或然而,许多是有效的)。

Using write/readUTF will write the length of the byte array as well as the data, so when you read it again it will know it only has to read the first 10 characters (or however many are valid).

这篇关于如何重新初始化一个分组的缓冲器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆